首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Martini的Golang :模拟测试示例

Martini的Golang :模拟测试示例
EN

Stack Overflow用户
提问于 2015-04-09 19:26:42
回答 1查看 2.5K关注 0票数 1

我已经把一段代码拼凑在一起,这样就可以在我的路线上取得进展。我想用嘲弄来测试这个。我是一个上进出出的新手,所以任何的提示都是非常感谢的。

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

代码语言:javascript
复制
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中是这样的:

代码语言:javascript
复制
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)
}

我的怀疑是:

  1. 考虑到我试图注入依赖,这里的嘲讽是如何工作的?
  2. 我应该从哪里开始测试,也就是说,应该在生成路由中模拟r.Get吗?现在,我已经这样做了,但是由于我使用的是Martini来处理所有的路由和请求,如果我所做的是对的,我就会被引用。

state_test.go:

代码语言:javascript
复制
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
}

我提到的链接:

  1. /担架/作证/模拟医生
  2. 1的例子。
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-04-09 22:51:34

为了执行依赖注入,要测试的东西需要有某种方式来接收它的依赖项。在您的代码中,与mongodb的连接是在初始化测试自身的过程中完成的,这不允许在模拟的同时注入一些看起来像mongo连接的东西。

实现依赖关系的方法有很多种,但最简单和最直接的方法之一是在创建依赖项时使其进行测试以接收依赖项,这样它的上下文就是配置依赖项的特定实现的位置。看看这个例子

代码语言:javascript
复制
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的实现才能工作,它不需要知道它的内部结构,唯一重要的是它实现了接口,同时使用了GetSet这两种方法。实际上,作为单元测试中的一般规则,您只想测试代码,而不是测试依赖项。在本例中,它在“生产”中使用Redis,但在测试中:

代码语言:javascript
复制
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)
}

除了让框架检查它是否已被调用之外,它只是没有任何功能。在测试本身中,您必须将期望配置为以下内容:

代码语言:javascript
复制
d := new(MockedDataStore)
...
d.On("Set", "foo", "42").Return().Once()
...
d.On("Get", "foo").Return("42").Once()

当然,用模拟的东西初始化实例,并测试它:

代码语言:javascript
复制
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)

因此,作为一个总结,更具体地回答你的问题:

  1. 您需要使您的实例能够使用其依赖项进行初始化,例如创建一个接收依赖项并返回该实例的方法。然后模拟依赖项,然后从测试中使用模拟,而不是“真实的”。
  2. 使用martini提供的方法martini生成对HTTP请求的响应,使用httptest.NewRecorder()模拟响应的接收。当然,如果应用程序具有在HTTP接口之外使用的更复杂的功能,也可以将其作为正常方法进行测试。
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29547231

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档