Go Test

10 min

何时编写测试,测试文件应放在哪里,有哪些测试类型,以及测试语法的基础。

1. 基础知识!

1.1 为什么不选择TDD

goland自带的生成也可以替代gotests参考一下最佳实践

测试驱动开 发(TDD)是一种软件开发过程,其中开发者先编写测试用例,然后编写满足这些测试用例的代码。TDD鼓励开发者从用户的角度来考虑功能,有助于创建更清晰、更可维护的代码。

然而,在某些情况下,直接编写业务代码然后再为其生成测试用例可能更加高效,特别是在以下情况:

  • 项目初期不清楚具体需求:在项目早期,需求可能还不够明确,直接编写业务代码探索可能的解决方案,之后再补充测试用例,可以更快地进行原型开发。
  • 快速迭代开发:在快速迭代的开发过程中,先快速实现功能,然后再回过头来确保代码质量,可能更符合项目节奏。
  • 遗留代码增加测试:对于已有的遗留代码,gotests提供了一种快速为这些代码补充测试用例的方法,提高代码质量。

gotests通过自动化生成测试用例的方式,减少了编写测试代码的时间和精力,使得开发者可以更专注于业务逻辑的实现,同时也确保了代码的可测试性和质量。

1.2 测试文件的位置

  • 在Go语言中,测试文件通常位于与被测试代码相同的包内。

  • 按照惯例,测试文件的名称以_test.go结尾。

    • 例如,如果你的源代码文件名为calculator.go,相应的测试文件名应为calculator_test.go
  • 示例结构

    假设你的项目结构如下:

    /user
        login.go
        record.go
    /model
    	usermodel.go

    对应的测试文件应该放置如下:

    /user
    	login.go
        login_test.go  # 测试 user 包中的 login 接口相关函数
        record.go
        record_test.go  # 测试 user 包中的 record 接口相关函数
    /model
    	usermodel.go
        usermodel_test.go  # 测试 model 包中的函数

    为什么这样组织

    • 可访问性:将测试文件放在与被测试代码相同的包中,可以无缝访问包内的所有函数和变量,包括未导出的私有函数和变量。这对于单元测试尤其重要。
    • 清晰的结构:这种组织方式保持了代码和测试的紧密关联,使得维护和查找相关测试变得更加容易。
    • 简化导入:测试文件与被测试代码在同一个包中,减少了导入依赖的复杂性。

1.3 测试类型

为了保证单测的价值长期有效,我们要 尽可能地屏蔽外部系统的依赖;而对外部依赖的测试,尽可能地交由更高层面的接口测试、功能测试、系统联调等途径去保障。——junedayday

Go语言支持多种类型的测试,主要包括:

  • 单元测试:测试代码中最小的单元,如函数或方法。
  • 基准测试(Benchmarks):测试代码的性能,如运行时间和内存使用。
  • 示例测试:提供示例代码,这既是文档也是可以执行的测试。
  • 安全测试
    • 检查应用是否有安全漏洞,如SQL注入、XSS攻击、权限泄露等。
    • 可以使用自动化工具辅助进行安全扫描。

1.4 mock/打桩

在软件测试中,“mocking”和”stubbing”(打桩)是两种常用的技术用于模拟或替代测试中的某些组件.

相似之处

  1. 替代真实依赖:无论是mock还是stub,它们都用于替代测试中的真实依赖,如外部服务、数据库等,以便于测试环境的搭建和测试用例的执行。
  2. 控制测试环境:通过使用mock和stub,可以控制测试环境,避免外部因素的干扰,确保测试的一致性和可重复性。
  3. 预设返回值:它们都允许预设方法的返回值,使得被测试的代码能够在一个可预测的环境中运行。

关键区别

  1. 目的和关注点
    • Mock:更侧重于验证交互,即验证被测试的代码是否以正确的方式使用了它的依赖。这包括方法调用的验证、参数验证、调用次数验证等。
    • Stub:主要用于提供必要的响应,不关注被测试代码与依赖之间的交互细节。Stub通常用于为测试提供必要的环境,如返回固定的数据或状态。
  2. 使用场景
    • Mock:当你需要验证代码的行为,特别是与依赖之间的交互时,使用mock。例如,验证一个方法是否被调用,或者调用时是否传递了正确的参数。
    • Stub:当你只需要依赖返回特定的数据或状态,而不需要验证交互细节时,使用stub。例如,当测试的函数需要依赖返回特定的值才能继续执行时。

选择Mock还是Stub

  • 如果你的测试目标是验证代码是否以正确的方式与外部依赖交互(如是否调用了某个方法,调用时是否传递了正确的参数),那么应该选择使用mock。
  • 如果你的测试目标仅仅是需要从依赖中获取特定的数据或状态,而不关心这些数据或状态是如何产生的,那么使用stub会更简单、更直接。

2. 实际操作

2.1 **gotests**的使用

goland直接生成也可以有一样的效果

2.11 安装gotests

首先,你需要安装gotests。如果你的开发环境已经配置了Go,可以通过下面的命令来安装gotests

go get -u github.com/cweill/gotests/...

这条命令会从GitHub下载并安装gotests

2.12 使用gotests生成测试用例

安装完成后,你可以开始为你的Go文件生成测试用例了。gotests的基本用法非常简单,只需要指定你想要生成测试用例的Go文件即可。如果你想为所有函数和方法生成测试用例,并直接写入到相应的测试文件中,可以使用以下命令:

gotests -all -w XXX.go

这里的XXX.go是你的源文件名。命令中的参数含义如下:

  • -all:为文件中的所有函数和方法生成测试用例。

  • -w:直接将生成的测试用例写入到测试文件中。如果测试文件不存在,gotests会自动创建。

2.2 Gomock 使用

1.4 使用 Gomock 进行单元测试 - 跟煎鱼学 Go (gitbook.io)

  • 生成命令

    mockgen -source=源文件地址 -destination=生成文件地址 -package=包名

总结

学习go test和测试相关知识是一个循序渐进的过程。从基本的单元测试开始,逐步学习如何测试不同类型的代码,然后掌握更高级的测试技巧和模式。记住,测试不仅仅是找出错误,更是关于设计和构建可靠、可维护的软件系统。通过实践和不断学习,你会发现测试能显著提升你的开发效率和代码质量。

参考资料