Golang中SQLite函数测试遇到问题如何解决
Golang中SQLite函数测试遇到问题如何解决 各位Gopher们!我发帖是因为在我的第一个Go项目good中需要大量帮助。基本上,这是一个与SQLite数据库交互的情绪追踪器。
我的问题是:我一直在处理sqlite_test.go,发现测试会以不同方式失败,具体取决于我是否使用TestMain(稍后会详细说明)。
首先,这是sqlite.go——在test1和test2分支中内容相同。现在,这是我在test1中的测试情况,其中每个测试相对独立(虽然也有些混乱)。
=== RUN TestInsertEvents
=== RUN TestInsertEvents/2006-01-02_15:04:05+00:00
=== RUN TestInsertEvents/2019-06-27_19:25:09-07:00
--- PASS: TestInsertEvents (0.00s)
--- PASS: TestInsertEvents/2006-01-02_15:04:05+00:00 (0.00s)
--- PASS: TestInsertEvents/2019-06-27_19:25:09-07:00 (0.00s)
=== RUN TestEvents
=== RUN TestEvents/reviewing_1_day_back
DEBU[0000] Getting all events starting from 2019-06-26.
DEBU[0000] Querying activities for event 1.
--- FAIL: TestEvents (0.00s)
--- FAIL: TestEvents/reviewing_1_day_back (0.00s)
sqlite_test.go:90: Error upon querying event: no such table: activities
FAIL
exit status 1
FAIL github.com/Goorzhel/good 0.004s
很奇怪,对吧?也许我可以把这归因于每个测试都在自己的goroutine中运行……说实话,我对这里发生的事情的心理模型还不够完善,无法准确判断到底是什么问题。但我非常确定activities表应该存在。
但等等,还有更奇怪的。这是test2,其中我使用了TestMain。
=== RUN TestInsertEvents/2006-01-02_15:04:05+00:00
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x61d31a]
goroutine 8 [running]:
testing.tRunner.func1(0xc00010e200)
/usr/lib/go/src/testing/testing.go:830 +0x392
panic(0x754c60, 0xa09f00)
/usr/lib/go/src/runtime/panic.go:522 +0x1b5
database/sql.(*DB).conn(0x0, 0x801b80, 0xc0000140a8, 0x1, 0x0, 0x0, 0x0)
/usr/lib/go/src/database/sql/sql.go:1080 +0x3a
database/sql.(*DB).query(0x0, 0x801b80, 0xc0000140a8, 0xc00001e1b0, 0x29, 0x0, 0x0, 0x0, 0xa28101, 0x7f0f35936008, ...)
/usr/lib/go/src/database/sql/sql.go:1513 +0x66
database/sql.(*DB).QueryContext(0x0, 0x801b80, 0xc0000140a8, 0xc00001e1b0, 0x29, 0x0, 0x0, 0x0, 0x40, 0xc00001e1b0, ...)
/usr/lib/go/src/database/sql/sql.go:1495 +0xd1
database/sql.(*DB).QueryRowContext(...)
/usr/lib/go/src/database/sql/sql.go:1596
database/sql.(*DB).QueryRow(0x0, 0xc00001e1b0, 0x29, 0x0, 0x0, 0x0, 0x29)
/usr/lib/go/src/database/sql/sql.go:1607 +0x8d
github.com/Goorzhel/good.(*dbConn).IDByName(0xa264d8, 0x7a52a8, 0x5, 0x7a5302, 0x5, 0x539, 0x877c38, 0x9eb564)
/home/ca/projects/good/sqlite.go:80 +0x1ed
github.com/Goorzhel/good.(*dbConn).InsertEvent(0xa264d8, 0xa0e840, 0x5d157c36, 0xc000048f98)
/home/ca/projects/good/sqlite.go:159 +0x72
github.com/Goorzhel/good.testInsertEventFunc.func1(0xc00010e200)
/home/ca/projects/good/sqlite_test.go:73 +0x37
testing.tRunner(0xc00010e200, 0xc00000e800)
/usr/lib/go/src/testing/testing.go:865 +0xc0
created by testing.(*T).Run
/usr/lib/go/src/testing/testing.go:916 +0x35a
exit status 2
FAIL github.com/Goorzhel/good 0.005s
哇!它段错误了!我就知道good.dbConn.IDByName有问题。但是,除了用go-delve/delve随便戳戳之外,我找不出问题所在。(我再次把这归因于我是Go新手,而且对调试堆栈跟踪完全没有经验,还有编写单元测试也不熟练,但我跑题了。)
最奇怪的是,只有在go test时我才会看到问题。现在你可以克隆源代码,go build它,然后正常运行程序而不会看到任何问题。
我有点怀疑问题可能是我完全忽略了database/sql.Tx功能,但我不想再次搞错而白费功夫。
总之,Gopher们,你们能帮我从这个坑里爬出来吗?
附言:很可能在我解决这个问题之后,我会重新设置更改并删除这些分支——如果你们希望我把相关部分放在Gist或类似的地方,请告诉我。
更多关于Golang中SQLite函数测试遇到问题如何解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html
@kync 说得有道理:从逻辑上讲,如果不先插入事件,我无法对单元进行测试 db.Events()。
这正是我需要摆脱那些反复困扰自己的陷阱的动力,其中包括我坚持使用内存 SQLite 数据库的做法。我最终选择使用一个稍后会被 os.Remove 删除的文件。
现在,我所有的测试都通过了,可以继续专注地构建这个东西了:
% go test
PASS
ok github.com/Goorzhel/good 0.125s
感谢大家!
更多关于Golang中SQLite函数测试遇到问题如何解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
感谢提供的链接,但正如我在帖子中提到的,我的问题特别针对Go代码的测试:
最奇怪的是,只有在执行
go test时才会出现故障。目前你可以克隆源代码,执行go build编译,然后正常运行程序而不会出现任何问题。
在单线程环境(编译后的二进制文件)中,基础的读写操作都没有出现问题。但根据我粗略的阅读,每个测试都在各自的goroutine中运行。
所以,我可能遇到了某种竞态条件,但目前我还没有找到解决方法。
(我可以不修复这个问题继续推进,但我希望让这些测试正常工作,这样就不必依赖手动运行工具了。)
Go语言中的测试函数默认不会按顺序执行。
你需要付出一些努力才能让它们按顺序运行。
T和B的Run方法允许定义子测试和子基准测试,无需为每个测试单独定义函数。这使得可以实现诸如表驱动基准测试和创建分层测试等用途。它还提供了一种共享通用设置和清理代码的方法:
func TestFoo(t *testing.T) { // t.Run("A=1", func(t *testing.T) { … }) t.Run("A=2", func(t *testing.T) { … }) t.Run("B=1", func(t *testing.T) { … }) // }每个子测试和子基准测试都有唯一的名称:由顶层测试的名称和传递给Run的名称序列组合而成,用斜杠分隔,可选的后缀序列号用于消除歧义。
-run和-bench命令行标志的参数是一个非锚定的正则表达式,用于匹配测试的名称。对于具有多个斜杠分隔元素的测试(如子测试),参数本身也是斜杠分隔的,表达式依次匹配每个名称元素。由于它是非锚定的,空表达式匹配任何字符串。例如,使用"匹配"表示"名称包含":
go test -run '' # 运行所有测试 go test -run Foo # 运行匹配"Foo"的顶层测试,例如"TestFooBar" go test -run Foo/A= # 对于匹配"Foo"的顶层测试,运行匹配"A="的子测试 go test -run /A=1 # 对于所有顶层测试,运行匹配"A=1"的子测试
https://tip.golang.org/pkg/testing/#hdr-Subtests_and_Sub_benchmarks


