Go单元测试编写的五个建议

Wesley13
• 阅读 299

测试驱动开发是保持高代码质量的好方法,同时保护自己免于回归,并向自己和其他人证明自己的代码完成了预期的工作。 这里有五个技巧和窍门可以改善你的测试。

把你的测试放在一个不同的包里

Go坚持同一个文件夹中的文件属于同一个包,除了_test.go文件。将测试代码移出软件包,可以让您编写测试,就好像您是软件包的真正用户。你不能摆弄内部,而是专注于暴露的界面,并总是想着你可能会添加到你的API的任何噪音。
Go单元测试编写的五个建议
这样可以让你自由地更改内部,而无需调整测试代码。

在不同的文件中进行内部测试

如果你确实需要对一些内部进行单元测试,用_internal_test.go作为后缀创建另一个文件。内部测试必然比接口测试更脆弱, 但是它们是确保内部组件行为的一个很好的方法,而且如果你使用测试驱动开发的话,它是特别有用的。

Go单元测试编写的五个建议

运行所有测试保存

去建立和运行速度非常快,所以没有任何理由可以说为什么不每次保存时都运行整个测试case。

当你在这个时候,为什么不去同时运行go vet,golint和goimports呢?

在Sublime Text中,这可以通过安装GoSublime并在添加以下配置项之前按下 Cmd +.,5来实现:

“on_save”: [{
  “cmd”: “gs9o_run_many”, “args”: {
    “commands”:[
      [“clear”],
      [“sh”, “if [ -f onsave.sh ]; then ./onsave.sh; else gofmt -s -w ./ && go build . errors && go test -i && go test && go vet && golint ; fi”]
    ],
    “focus_view”: false
  }
}],
“fmt_cmd”: [“goimports”]

上面的脚本首先检查项目是否有一个onsave.sh文件,它会运行。这使您可以轻松关闭不适用的软件包的自动测试功能。

写表驱动的测试

匿名结构和复合文字允许我们写出非常清晰和简单的表格测试,而不依赖任何外部包。 下面的代码允许我们为一个尚未写成的“Fib”函数设置一系列的测试:

var fibTests = [] struct { 
  n int // input 
  expected int //预期结果
} { 
  {1,1},
  {2,1},
  {3,2},
  {4,3},
  {5,5},
  {6,8},
  {7,13},
}

然后,我们的测试函数只是覆盖在切片上,在声明结果正确之前为每个“n”调用“Fib”方法:

func TestFib(t *testing.T) {
  for _, tt := range fibTests {
    actual := Fib(tt.n)
    if actual != tt.expected {
      t.Errorf("Fib(%d): expected %d, actual %d", tt.n, tt.expected, actual)
    }
  }
}

看看你是否可以自己写“Fib”函数来让测试通过,或者你可以从Dave Chaney那里找到解决方法。

使用Go代码模拟接口

如果你需要模拟你的代码依赖的东西来正确地测试它,那么很可能是一个接口的好选择。即使你依赖于一个你不能改变的外部包,你的代码仍然可以使用一个外部类型将会满足的接口。

经过几年的写mocks接口,我终于找到了模拟接口的完美方式,而不需要添加任何依赖项到我们的项目中: [check out Moq](https://medium.com/@matryer/meet-moq-easily-mock-interfaces-in-go-476444187d10)。

假设我们正在导入这个外部包:

package mailman
import “net/mail”
type MailMan struct{}
func (m *MailMan) Send(subject, body string, to ...*mail.Address) {
  // some code
}
func New() *MailMan {
  return &MailMan{}
}

如果我们正在测试的代码需要一个MailMan对象,我们的测试代码可以调用它的唯一方法是提供一个实际的MailMan实例。

func SendWelcomeEmail(m * MailMan,to ... * mail.Address){...}

这意味着每当我们运行我们的测试,一个真正的电子邮件可以发送。想象一下,如果我们已经实现了上面的保存功能。我们很快就会惹恼我们的测试用户,或者拿出一大笔服务费用。 另一种方法是将这个简单的接口添加到您的代码中:

type EmailSender interface{
  Send(subject, body string, to ...*mail.Address)
}

当然,MailMan已经满足了这个接口,因为我们首先从他的Send方法签名 - 所以我们仍然可以像以前一样传入MailMan对象。 但现在我们可以写一个测试邮件发件人:

type testEmailSender struct{
  lastSubject string
  lastBody    string
  lastTo      []*mail.Address
}
// make sure it satisfies the interface
var _ package.EmailSender = (*testEmailSender)(nil) 
func (t *testEmailSender) Send(subject, body string, to ...*mail.Address) {
  t.lastSubject = subject
  t.lastBody = body
  t.lastTo = to
}

现在我们可以更新我们的SendWelcomeEmail函数来取接口,而不是具体的类型:

func SendWelcomeEmail(m EmailSender,to ... * mail.Address){...}

在我们的测试代码中,我们可以发送我们的假发送者,并在调用目标函数之后在这些字段上进行断言:

func TestSendWelcomeEmail(t *testing.T) {
  sender := &testEmailSender{}
  SendWelcomeEmail(sender, to1, to2)
  if sender.lastSubject != "Welcome" {
    t.Error("Subject line was wrong")
  }
  if sender.To[0] != to1 && sender.To[1] != to2 {
    t.Error("Wrong recipients")
  }
}

如果你想进一步探索mock特性,那么一定要看看check out Moq, 它不仅描述了一个写模拟的好方法,而且还为你写。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
2年前
java单元测试
Java单元测试1.概述java单元测试是最小的功能单元测试代码,单元测试就是针对单个java方法的测试。java程序的最小功能单元是方法。main方法进行测试的缺点:只能有一个main()方法,不能把测试代码分离出来无法打印出测试结果和期望结果.例如:expected:
Wesley13 Wesley13
2年前
java单元测试工具
前言随着DevOp的不断流行,自动化测试慢慢成为Java开发者的关注点。因此,本文将分享10款优秀的单元测试框架和库,它们可以帮助Java开发人员在其Java项目上编写单元测试和集成测试。1\.JUnit我绝对JUnit不需要太多的介绍了。即使您是Java初学者,也可能听说过它。它可以帮助您为Java代码编写单元测试。几
凯文86 凯文86
3年前
Spring Boot API 服务测试指南
SpringBoot除了简化了Spring应用的开发,同时也简化了Spring应用的测试。它内置支持各种常用测试工具,包括SpringTest、JUnit、TestNG、Mockito、AssertJ等。本文将讲解如何编写单元测试和集成测试来保障SpringBootAPI应用不同层级代码的质量,其中会涉及到使用嵌入式的H2数据库
云原生引擎单元测试实践
快速迭代的开发工作中如何提高代码质量一直是团队痛点,特别是没有测试支持的开发团队。合理的使用单元测试,并关注单元测试通过率、代码覆盖率可以有效提高代码质量。今天就来讲讲云原生引擎单元测试实践。
万木春 万木春
1年前
高效易用的C++单元测试框架:轻松构建高质量代码
单元测试是构建稳定、高质量的程序、服务或系统的必不可少的一环。通过单元测试,我们可以在开发过程中及时发现和修复代码中的问题,提高代码的质量和可维护性。同时,单元测试也可以帮助我们更好地理解代码的功能和实现细节,从而更好地进行代码重构和优化。
Stella981 Stella981
2年前
Golang代码测试:一点到面用测试驱动开发
摘要:TDD(TestDrivenDevelopment),测试驱动开发。期望局部最优到全局最优,这个是一种非常不错的好习惯。了解Golang的测试之前,我们先了解一下go语言自带的测试工具。gotest工具Go语言中的测试依赖gotest命令。编写测试代码和编写普通的Go代码过程是类似的,并不需要学习新的
Stella981 Stella981
2年前
Spring Boot 教程
1\.应用测试的介绍一般我们在写完代码之后,代码的测试是会给专门的测试人员来测试的,如果一个测试跑到你的工位上对你说,你的代码好像有Bug,你肯定会不爽,反正我就是这样的🙃。所以为了显示自己的代码质量高一点,在功能提交给测试之前,我们会自己测试一下,接下来给大家介绍一下SpringBootTest应用测试框架。Spr
京东云开发者 京东云开发者
8个月前
Java单元测试及常用语句 | 京东物流技术团队
编写Java单元测试用例,即把一段复杂的代码拆解成一系列简单的单元测试用例,并且无需启动服务,在短时间内测试代码中的处理逻辑。写好Java单元测试用例,其实就是把“复杂问题简单化,建单问题深入化“。在编写的过程中,我们也可以对自己的代码进行一个二次检查。