Testing Golang with Martini:模拟测试示例

Testing Golang with Martini:模拟测试示例,testing,go,mocking,martini,Testing,Go,Mocking,Martini,我已经整理了一段代码,它不会影响我的路线。我想用mocking测试一下。我是一个能干的测试能手,所以任何提示都非常感谢 My Generate Routes.go为当前URL生成路由。 片段: 这是在my server.go中调用的: var configuration = app.LoadConfiguration(os.Getenv("MYENV")) // Our Martini API Instance var apiInstance *martini.Martini func in

我已经整理了一段代码,它不会影响我的路线。我想用mocking测试一下。我是一个能干的测试能手,所以任何提示都非常感谢

My Generate Routes.go为当前URL生成路由。 片段:

这是在my 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)
}
我的疑问是:

  • 考虑到我正在尝试注入依赖性,这里的模拟是如何工作的

  • 我应该从哪里开始测试,即我应该模拟r.进入生成路线?现在,我已经这样做了,但因为我使用的是马提尼酒,它可以处理所有的路由和请求,如果我所做的是正确的,我会很困惑

  • 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
    }
    
    我提到的链接:


  • 为了进行依赖项注入,要测试的东西需要有某种方式来接收其依赖项。在您的代码中,到mongodb的连接是在测试自身的初始化过程中完成的,这不允许在模拟的情况下注入看起来像mongo连接的东西

    实现依赖关系的方法有很多,但是进行依赖关系注入的最简单和最直接的方法之一是,在创建依赖关系时,让要测试的东西接收依赖关系,这样它的上下文就是配置依赖关系的具体实现的地方。看看:

    实例需要实现一个
    数据存储
    才能工作,它不需要知道任何关于其内部的信息,唯一重要的是它使用两种方法实现接口,
    Get
    Set
    。实际上,作为单元测试的一般规则,您只想测试代码,而不想测试依赖项。在本例中,它在“生产”中使用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接口之外使用的更复杂的功能,您也可以将其作为常规方法进行测试


  • 非常感谢你!这就是我要找的。一旦我决定实施它,我会有更多的问题。如果我真的卡住了,我还能在这个帖子里打扰你吗?当然,没问题,一点也不麻烦,我也从Go开始:)
    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)