当前位置: 首页 > 科技观察

在Go中使用Dockertest进行集成测试

时间:2023-03-13 20:41:03 科技观察

集成测试(或系统测试)通常意味着有一个填充有数据的数据库,如redis、elasticsearch等,通常,我们的软件与之交互的任何基础设施都可以工作。最常见的方式是复制我们的生产基础设施,用容器实现起来相对容易,比如docker容器。我们可以为每个需要复制的服务设置和运行一个容器,我们可以使用docker-compose来编排它并创建一些makefile或只是一个简单的脚本来准备基础设施和运行集成测试。如果您的测试是独立的(它们应该是),您将必须找到在测试之间“重启”基础设施服务的方法,这很难通过单独的基础设施设置和测试(基础设施在脚本中设置),和Go文件中的测试)01dockertest如果你正在使用Go,你可以使用dockertest,一个可以在Go测试文件中管理和编排容器的库。从Go文件管理测试基础设施容器,允许我们控制每个测试中我们需要的服务(例如,一些包正在使用数据库而不是Redis,并且为这个测试运行Redis没有意义)安装dockertest要安装dockertest,只需运行:goget-ugithub.com/ory/dockertest/v3使用dockertest使用dockertest设置基础设施的最简单方法是在测试文件的TestMain函数中添加设置代码。TestMain是在包中运行测试之前调用的函数,更多信息在这里。这是如何使用dockertest设置MySQL服务的示例:packagemypackage_testimport("database/sql""fmt""log""os""testing"_"github.com/go-sql-driver/mysql""github.com/ory/dockertest/v3")vardb*sql.DBfuncTestMain(m*testing.M){//usesasensibledefaultonwindows(tcp/http)andlinux/osx(socket)pool,err:=dockertest.NewPool("")iferr!=nil{log.Fatalf("Couldnotconnecttodocker:%s",err)}//pullsanimage,createsacontainerbasedonitandrunsitresource,err:=pool.Run("mysql","5.7",[]string{"MYSQL_ROOT_PASSWORD=secret"})iferr!=nil{log.Fatalf("Couldnotstartresource:%s",err)}//指数回退-重试,因为容器中的应用程序可能还没有准备好接受连接syetiferr:=pool.Retry(func()error{varerrerrordb,err=sql.Open("mysql",fmt.Sprintf("root:secret@(localhost:%s)/mysql",resource.GetPort("3306/tcp")))iferr!=nil{returnerr}returndb。Ping()});err!=nil{log.Fatalf("Couldnotconnecttodocker:%s",err)}//RESERVEDFORDATABASEMIGRATIONScode:=m.Run()//你不能推迟这个因为os.Exit不关心deferiferr:=pool.Purge(resource);err!=nil{log.Fatalf("Couldnotpurgeresource:%s",err)}os.Exit(code)}填充数据库,现在我们有可用的数据库服务,但这个数据库是空的dockertest正在用于容器通用MySQL映像,与我们的应用程序无关。我之前写过一篇关于数据库迁移的文章,在那篇文章中,我谈到了go-migrate,一个运行数据库迁移的工具,那篇文章,我专注于将它用作CLI工具,现在将在我们的Go代码中使用它.我们将之前编写的代码添加到此代码中//RESERVEDFORDATABASEMIGRATIONS:m,err:=migrate.NewWithDatabaseInstance("file://,"mysql",driver)iferr!=nil{log.Fatalf("Errorrunningmigrations:%s",err)}err=m.Up()iferr!=nil{log.Fatal(err.Error())}然后在dockertestup数据库后,迁移工具填充数据库,我们的集成测试可以使用数据库中的相同数据运行。如果应用程序有多个包(这是常见的情况),我会将服务的设置代码放在一个单独的文件中,该文件在每个包中调用://it_utils.gopackageit_utilsfuncIntegrationTestSetup()(*dockertest.Pool,*[]dockertestResource{//Setuptheservices//returnthepoolandtheresources}funcIntegrationTestTeardown(pool*dockertest.Pool,resources[]*dockertest.Resource){for_,resource:=rangeresources{iferr:=pool.Purge(resource);err!=nil{fmt.Printf("Couldnotpurgeresource:%s\n",err)}}}然后我们只需要在每个包的测试中加入如下代码:packagemy_packagefuncTestMyTests(t*testing.T){iftesting.Short(){t.Skip()}pool,resources:=itutils.IntegrationTestSetup()deferitutils.IntegrationTestTeardown(pool,resources)t.Run("yourtest",func(t*testing.T){...}}funcTestOtherTests(t*testing.T){iftesting.Short(){t.Skip()}pool,resources:=itutils.IntegrationTestSetup()deferitutils.IntegrationTestTeardown(pool,resources)t.Run("yoourothertest",func(t*testing.T){..。}}做这个以这种方式在每个测试块上,服务在一个新容器中运行,使测试完全独立。作为最后的提示,我建议将集成测试放在不同的包中以避免循环导入。原文链接:https://sergiocarracedo.es/integration-tests-in-golang-with-dockertest/本文转载自微信公众号“幽灵”,可通过以下二维码关注。转载本文请联系有鬼公众号。