我整理了一段代码,在我的路线上执行 GET。我想用模拟来测试这个。我是围棋和测试菜鸟,所以非常感谢任何提示。
My Generate Routes.go 为当前 URL 生成路由。 片段:
func (h *StateRoute) GenerateRoutes (router *martini.Router) *martini.Router {
r := *router
/**
* Get all states
*
*/
r.Get("/state", func( enc app.Encoder,
db abstract.MongoDB,
reqContext abstract.RequestContext,
res http.ResponseWriter,
req *http.Request) (int, string) {
states := []models.State{}
searchQuery := bson.M{}
var q *mgo.Query = db.GetDB().C("states").Find(searchQuery)
query, currentPage, limit, total := abstract.Paginate(req, q)
query.All(&states)
str, err := enc.EncodeWithPagination(currentPage, limit, total, states)
return http.StatusOK, app.WrapResponse(str, err)
})
}
这在我的 server.go 中是这样调用的:
var configuration = app.LoadConfiguration(os.Getenv("MYENV"))
// Our Martini API Instance
var apiInstance *martini.Martini
func init() {
apiInstance = martini.New()
// Setup middleware
apiInstance.Use(martini.Recovery())
apiInstance.Use(martini.Logger())
// Add the request context middleware to support contexual data availability
reqContext := &app.LRSContext{ }
reqContext.SetConfiguration(configuration)
producer := app.ConfigProducer(reqContext)
reqContext.SetProducer(producer)
apiInstance.MapTo(reqContext, (*abstract.RequestContext)(nil))
// Hook in the OAuth2 Authorization object, to be processed before all requests
apiInstance.Use(app.VerifyAuthorization)
// Connect to the DB and Inject the DB connection into Martini
apiInstance.Use(app.MongoDBConnect(reqContext))
// Add the ResponseEncoder to allow JSON encoding of our responses
apiInstance.Use(app.ResponseEncoder)
// Add Route handlers
r := martini.NewRouter()
stateRouter := routes.StateRoute{}
stateRouter.GenerateRoutes(&r)
// Add the built router as the martini action
apiInstance.Action(r.Handle)
}
我的疑问:
考虑到我正在尝试注入(inject)依赖项,这里的模拟如何工作?
我应该从哪里开始测试,即我应该在生成路由中模拟 r.Get 吗?现在,我已经做到了这一点,但由于我使用的是处理所有路由和请求的 Martini,如果我所做的是正确的,我会失去报价吗?
state_test.go:
type mockedStateRoute struct {
// How can I mock the stateRoute struct?
mock.Mock
}
type mockedEncoder struct {
mock.Mock
}
type mockedMongoDB struct {
mock.Mock
}
type mockedReqContext struct{
mock.Mock
}
type mockedRespWriter struct{
mock.Mock
}
type mockedReq struct{
mock.Mock
}
func (m *mockedStateRoute) testGetStatesRoute(m1 mockedEncoder,
m2 mockedMongoDB, m3 mockedReqContext,
m4 mockedReqContext, m5 mockedRespWriter,
m6 mockedReq) (string) {
args := m.Called(m1,m2,m3,m4,m5,m6)
fmt.Print("You just called /states/GET")
// 1 is just a test value I want to return
return 1, args.Error(1)
}
func TestSomething (t *testing.T) {
testObj := new(mockedStateRoute)
testObj.On("testGetStatesRoute", 123).Return(true,nil)
// My target function that does something with mockedStateRoute
// How can I call the GET function in GenerateRoutes(). Or should I, since martini is handling all my requests
}
我提到的链接:
最佳答案
为了进行依赖注入(inject),要测试的东西需要有某种方式来接收它的依赖。在您的代码中,与 mongodb 的连接是在初始化事物以测试自身时完成的,在模拟时不允许注入(inject)看起来像 mongo 连接的事物。
实现它的方法有很多种,但是进行依赖注入(inject)的最简单和最直接的方法之一是让要测试的东西在创建时接收依赖,这样它的上下文就是特定的地方配置依赖项的实现。看看this example :
type DataStore interface {
Get(k string) string
Set(k, v string)
}
type MyInstance struct {
*martini.Martini
}
func NewAppInstance(d DataStore) *MyInstance {
...
}
func main() {
d := NewRedisDataStore("127.0.0.1", 6379)
NewAppInstance(d).Run()
}
实例需要Datastore的实现才能工作,它不需要知道任何关于它的内部结构,唯一重要的是它实现了接口(interface),有两种方法,获取 和设置。事实上,作为单元测试的一般规则,您只想测试您的代码,而不是您的依赖项。在此示例中,它在“生产”中使用 Redis,但在测试中:
type MockedDataStore struct {
mock.Mock
}
func (m *MockedDataStore) Get(k string) string {
args := m.Called(k)
return args.String(0)
}
func (m *MockedDataStore) Set(k, v string) {
m.Called(k, v)
}
它只是一些没有任何功能的东西,除了让框架检查它是否已被调用。在测试本身中,您必须使用以下内容配置期望:
d := new(MockedDataStore)
...
d.On("Set", "foo", "42").Return().Once()
...
d.On("Get", "foo").Return("42").Once()
当然,用模拟的东西初始化实例,并测试它:
d := new(MockedDataStore)
instance := NewAppInstance(d)
d.On("Get", "foo").Return("42").Once()
request, _ = http.NewRequest("GET", "/get/foo", nil)
response = httptest.NewRecorder()
instance.ServeHTTP(response, request)
d.AssertExpectations(t)
因此,作为总结,请更具体地回答您的问题:
您需要使您的实例能够使用其依赖项进行初始化,例如创建一个接收依赖项并返回实例的方法。然后模拟依赖项并从测试中使用模拟而不是“真实”的。
使用martini提供的方法ServeHTTP生成对HTTP请求的响应,使用httptest.NewRecorder()模拟响应的接收。当然,如果您的应用程序具有更复杂的功能,这些功能是在 HTTP 接口(interface)之外使用的,您也可以将其作为常规方法进行测试。
关于testing - Golang 与 Martini : Mock testing example,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29547231/
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
在Test::Unit中的ruby单元测试断言失败后,在执行teardown之前,是否有一些简洁优雅的方法来立即执行我的代码?我正在做一些自动化的GUI测试,并希望在出现问题后立即截图。 最佳答案 如果您使用的是1.9,请不要使用Test::Unit::TestCase作为您的基类。对其进行子类化并覆盖#run_test以进行救援,截取屏幕截图并重新提出:classMyAbstractTestCase或者,我认为这实际上是最简洁的方法,您可以使用before_teardownHook:classMyTestCase这不适用于1.
显然在Test::Unit中没有assert_false。您将如何通过扩展断言并添加文件config/initializers/assertions_helper.rb来添加它?这是最好的方法吗?我不想修改test/unit/assertions.rb。顺便说一句,我不认为这是多余的。我使用的是assert_equalfalse,something_to_evaluate。这种方法的问题是很容易意外使用assertfalse,something_to_evaluate。这将始终失败,不会引发错误或警告,并且会在测试中引入错误。 最佳答案
我有一个基于1.8.7构建的应用程序,我正尝试在1.9.3的系统上启动它当我运行脚本/服务器时,我得到:/usr/local/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in`require':cannotloadsuchfile--test/unit/error(LoadError)from/usr/local/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in`require'我的服务器脚本如下所示:#!/usr/bin/envrubyrequireFile.expand_path('../.
我希望我的后台作业能够内联运行某些标记测试。我可以通过用perform_enqueueddo包装测试来做到这一点,但我希望能够用元数据标记它们,如果可能的话,它会自动发生。我试过以下方法:it"doeseverythinginthejobtoo",perform_enqueued:truedoendconfig.around(:each)do|example|ifexample.metadata[:perform_enqueued]perform_enqueued_jobsdoexample.runendendend但它会导致错误:undefinedmethod`perform_enq
我最近正在进行Rails5升级,当我尝试启动Rails控制台时遇到了这个错误:/actionpack-5.0.0/lib/action_controller/test_case.rb:49:ininitialize':wrongnumberofarguments(0for2)(ArgumentError)当前bundleupdaterails已经完成了gem依赖项的解决,足以更新到5.0.0,rspec正在运行(尽管我正在修复很多中断)。我也可以运行railss没有错误。这里是代码中断行:https://github.com/rails/rails/blob/master/action
我现在调用第三方网络服务作为我的应用程序的一部分。我正在使用RestClientgem来执行此操作。有大量工具可以用来做同样的事情,所以这应该无关紧要。我很好奇的是有足够好的测试,没有什么太花哨的,我可以在其中模拟当第三方Web服务出于任何原因不可用时我的应用程序如何响应。无论是我超出了速率限制还是由于网络延迟/并发症而超时,我只想能够获取HTTP状态代码之类的东西并测试我的应用程序在该事件中执行的操作。使用Test::Unit执行此操作的最佳方法是什么?现在,对第三方服务的调用封装在我的一个Controller中。我有一个简单的模块,其中包含一些用于远程服务不同端点的包装器方法。我只
如何在不使用sleep(1.second)方法的情况下编写规范?当我取消sleep时,我的测试会因为返回相同的时间戳而中断吗?我有以下类方法:defskipqs=find_or_create_by(user_id:user_id)qs.set_updated_atqs.n_skip+=1qs.save!end和以下规范:qs=skip(user.id)sleep(1.second)qs2=skip(user.id)qs.should_notbe_nilqs2.should_notbe_nil(qs.updated_at 最佳答案 我
当我在生产模式下运行我的Rails应用程序时出现以下错误,但是当我在开发模式下运行我的应用程序时它工作正常。我可以在生产模式下使用任何Gem吗?`require':Nosuchfiletoload--test_helper(LoadError)以下是完整的代码轨迹:/home/nyros/.rvm/gems/ruby-2.2.0@dfl/gems/activesupport-4.0.2/lib/active_support/dependencies.rb:229:in`require':Nosuchfiletoload--test_helper(LoadError)from/home/
我有一个使用Rails3.2和Devise的应用程序。我有一个使用rspec和Capybara的请求测试套件。我尝试在我的登录助手中改用Warden测试助手,而不是让Capybara填写登录表并提交。由于我的测试套件的大小和复杂性,这使我的测试运行时间节省了超过一分半钟。在我的配置中是:RSpec.configuredo|config|config.includeWarden::Test::Helpers,:type=>:requestconfig.after:eachdoWarden.test_reset!endend在上下文中:let!(:current_user){Factory