使用gomock和httptest测试api
Mock
Mock的关键:接口
mock的字面意思就是literally模拟一个对象。在软件中,mock的重点在于:不要求完全实现一模一样的功能,只要实现相同的接口即可。
它的原理是:假设被mock的对象是某接口的实现类,那么如果我的mock对象也实现该接口,我在test中就可以使用这个mock对象平替原对象。
Mock的用途
重要:Mock的对象必然不是我们要测试的对象。
Mock可以抽离出一些访问速度慢/不稳定/难以掌控返回值的对象。
比如说要测试web api,我们可以mock db,测试一下db返回error时,api是否应该返回对应的状态码。比如db返回ErrNoRow
时api应该返回404,否则返回500。
要在正常情况下db还是挺难返回不同的error的。但把db mock了之后就可以随意改db的返回值了。
mock对象虽然实现了一样的接口,但其函数返回值基本是dummy。但这是唯一的缺点。
mock的好处很多:我们可以mock函数的input,指定函数的output。我们还可以require每个函数被执行几次,等等。
gomock
gomock是一个mock代码生成器。具体来说就是为被mock的接口生成代码。
比如说我指定要为我的db:Store
接口生成mock,它就会生成一个MockStore类并实现所有Store接口函数。
stub
mock stub就是调用mock函数时写的一段代码,可以mock函数的input,指定函数的output, require每个函数被执行几次
,等等。
比如这段代码的意思是:store.GetAccount()这个函数,在input为(any, eq(acc.ID))的条件下必须只被调用一次,指定返回值为(db.Account{}, sql.ErrNoRows)。
store.EXPECT().
GetAccount(gomock.Any(), gomock.Eq(account.ID)).
Times(1).
Return(db.Account{}, sql.ErrNoRows)
httptest
主要用的是一个recorder
。它可以记录http调用的返回结果。
比如执行server.router.ServeHTTP(recorder, request)
就可以执行request
并且将结果记录在recorder
。