来自python世界的fixtures非常有用(Fixtures为可重用的状态/支持逻辑定义了一个Python契约,主要用于单元测试)。我想知道Golang中是否有类似的支持,允许我使用一些预定义的fixture来运行我的测试,比如设置服务器,拆除它,每次运行测试时执行一些重复的任务?有人能给我举一些在Golang做同样事情的例子吗?
发布于 2016-01-26 00:42:43
如果你想使用标准的Go测试工具,你可以定义一个带有签名TestMain(m *testing.M)的函数,并把你的fixture代码放在里面。
测试程序有时需要在测试之前或之后执行额外的设置或拆卸。测试有时也有必要控制哪些代码在主线程上运行。为了支持这些和其他情况,如果测试文件包含函数:
func TestMain(m *testing.M)
然后,生成的测试将调用TestMain(m),而不是直接运行测试。TestMain在主goroutine中运行,可以围绕m.Run调用执行任何必要的设置和拆卸操作。然后,它应该使用m.Run的结果调用os.Exit。调用TestMain时,flag.Parse尚未运行。如果TestMain依赖于命令行标志,它应该显式调用flag.Parse。
TestMain的一个简单实现是:
func TestMain(m *testing.M) { flag.Parse() os.Exit(m.Run()) }
发布于 2018-10-08 22:16:47
我知道这是一个古老的问题,但这仍然出现在搜索结果中,所以我想我应该给出一个可能的答案。
您可以将代码隔离到辅助函数中,这些辅助函数返回一个"teardown“函数,以便在其自身之后进行清理。以下是启动服务器并在测试用例结束时将其关闭的一种可能方法。
func setUpServer() (string, func()) {
h := func(w http.ResponseWriter, r *http.Request) {
code := http.StatusTeapot
http.Error(w, http.StatusText(code), code)
}
ts := httptest.NewServer(http.HandlerFunc(h))
return ts.URL, ts.Close
}
func TestWithServer(t *testing.T) {
u, close := setUpServer()
defer close()
rsp, err := http.Get(u)
assert.Nil(t, err)
assert.Equal(t, http.StatusTeapot, rsp.StatusCode)
}这将启动一个带有net/http/httptest的服务器,并返回它的URL以及一个充当“teardown”的函数。此函数被添加到延迟堆栈中,因此无论测试用例如何退出,都会始终调用它。
如果你有一个更复杂的设置,并且你需要处理错误,你可以选择传入*testing.T。这个例子展示了设置函数返回一个*url.URL而不是URL格式的字符串,解析可能会返回一个错误。
func setUpServer(t *testing.T) (*url.URL, func()) {
h := func(w http.ResponseWriter, r *http.Request) {
code := http.StatusTeapot
http.Error(w, http.StatusText(code), code)
}
ts := httptest.NewServer(http.HandlerFunc(h))
u, err := url.Parse(ts.URL)
assert.Nil(t, err)
return u, ts.Close
}
func TestWithServer(t *testing.T) {
u, close := setUpServer(t)
defer close()
u.Path = "/a/b/c/d"
rsp, err := http.Get(u.String())
assert.Nil(t, err)
assert.Equal(t, http.StatusTeapot, rsp.StatusCode)
}发布于 2021-08-27 23:00:21
我为use fixtures编写了类似于pytest的golang引擎:https://github.com/rekby/fixenv
使用示例:
package example
// db create database abd db struct, cached per package - call
// once and same db shared with all tests
func db(e Env)*DB{...}
// DbCustomer - create customer with random personal data
// but fixed name. Fixture result shared by test and subtests,
// then mean many calls Customer with same name will return same
// customer object.
// Call Customer with other name will create new customer
// and resurn other object.
func DbCustomer(e Env, name string) Customer {
// ... create customer
db(e).CustomerStore(cust)
// ...
return cust
}
// DbAccount create bank account for customer with given name.
func DbAccount(e Env, customerName, accountName string)Account{
cust := DbCustomer(e, customerName)
// ... create account
db(e).AccountStore(acc)
// ...
return acc
}
func TestFirstOwnAccounts(t *testing.T){
e := NewEnv(t)
// background:
// create database
// create customer bob
// create account from
accFrom := DbAccount(e, "bob", "from")
// get existed db, get existed bob, create account to
accTo := DbAccount(e, "bob", "to")
PutMoney(accFrom, 100)
SendMoney(accFrom, accTo, 20)
if accFrom != 80 {
t.Error()
}
if accTo != 20 {
t.Error()
}
// background:
// delete account to
// delete account from
// delete customer bob
}
func TestSecondTransferBetweenCustomers(t *testing.T){
e := NewEnv(t)
// background:
// get db, existed from prev test
// create customer bob
// create account main for bob
accFrom := DbAccount(e, "bob", "main")
// background:
// get existed db
// create customer alice
// create account main for alice
accTo := DbAccount(e, "alice", "main")
PutMoney(accFrom, 100)
SendMoney(accFrom, accTo, 20)
if accFrom != 80 {
t.Error()
}
if accTo != 20 {
t.Error()
}
// background:
// remove account of alice
// remove customer alice
// remove account of bob
// remove customer bob
}
// background:
// after all test finished drop databasehttps://stackoverflow.com/questions/34889721
复制相似问题