• 用GoConvey编写单元测试的一些总结


    一、尽量用Convey将所有测试用例的Convey汇总

    用Convey嵌套的方法,将所有测试用例的Convey用一个大的Convey包裹起来,每个测试函数下只有一个大的Convey。比如下面的示例代码:

    1. import (
    2. "testing"
    3. . "github.com/smartystreets/goconvey/convey"
    4. )
    5. func TestStringSliceEqual(t *testing.T) {
    6. Convey("TestStringSliceEqual", t, func() {
    7. Convey("should return true when a != nil && b != nil", func() {
    8. a := []string{"hello", "goconvey"}
    9. b := []string{"hello", "goconvey"}
    10. So(StringSliceEqual(a, b), ShouldBeTrue)
    11. })
    12. Convey("should return true when a == nil && b == nil", func() {
    13. So(StringSliceEqual(nil, nil), ShouldBeTrue)
    14. })
    15. Convey("should return false when a == nil && b != nil", func() {
    16. a := []string(nil)
    17. b := []string{}
    18. So(StringSliceEqual(a, b), ShouldBeFalse)
    19. })
    20. Convey("should return false when a != nil && b != nil", func() {
    21. a := []string{"hello", "world"}
    22. b := []string{"hello", "goconvey"}
    23. So(StringSliceEqual(a, b), ShouldBeFalse)
    24. })
    25. })
    26. }

    这样做的好处是,看单测结果更为清晰直观:

    1. === RUN TestStringSliceEqual
    2. TestStringSliceEqual
    3. should return true when a != nil && b != nil
    4. should return true when a == nil && b == nil
    5. should return false when a == nil && b != nil
    6. should return false when a != nil && b != nil
    7. 4 total assertions
    8. --- PASS: TestStringSliceEqual (0.00s)
    9. PASS
    10. ok infra/alg 0.006s

    二、用GWT结构来描述复杂的测试用例

    GWT结构嵌套了三层Convey:最外层是Given层,用来给定测试用例需要的数据;中间一层是When层,用来执行被测试的函数方法,得到result;最内层是Then层,用So来对result进行断言,看结果是否满足期望。

    1 示例代码

    示例代码如下:

    1. func TestStringSliceEqualIfBothNil(t *testing.T) {
    2. Convey("Given two string slice which are both nil", t, func() {
    3. var a []string = nil
    4. var b []string = nil
    5. Convey("When the comparision is done", func() {
    6. result := StringSliceEqual(a, b)
    7. Convey("Then the result should be true", func() {
    8. So(result, ShouldBeTrue)
    9. })
    10. })
    11. })
    12. }
    13. func TestStringSliceNotEqualIfNotBothNil(t *testing.T) {
    14. Convey("Given two string slice which are both nil", t, func() {
    15. a := []string(nil)
    16. b := []string{}
    17. Convey("When the comparision is done", func() {
    18. result := StringSliceEqual(a, b)
    19. Convey("Then the result should be false", func() {
    20. So(result, ShouldBeFalse)
    21. })
    22. })
    23. })
    24. }
    25. func TestStringSliceNotEqualIfBothNotNil(t *testing.T) {
    26. Convey("Given two string slice which are both not nil", t, func() {
    27. a := []string{"hello", "world"}
    28. b := []string{"hello", "goconvey"}
    29. Convey("When the comparision is done", func() {
    30. result := StringSliceEqual(a, b)
    31. Convey("Then the result should be false", func() {
    32. So(result, ShouldBeFalse)
    33. })
    34. })
    35. })
    36. }

    在实际运用中,可以结合第一条方法构成四层嵌套来描述一个测试用例:

    1. func TestStringSliceEqual(t *testing.T) {
    2. Convey("TestStringSliceEqualIfBothNotNil", t, func() {
    3. Convey("Given two string slice which are both not nil", func() {
    4. a := []string{"hello", "goconvey"}
    5. b := []string{"hello", "goconvey"}
    6. Convey("When the comparision is done", func() {
    7. result := StringSliceEqual(a, b)
    8. Convey("Then the result should be true", func() {
    9. So(result, ShouldBeTrue)
    10. })
    11. })
    12. })
    13. })
    14. Convey("TestStringSliceEqualIfBothNil", t, func() {
    15. Convey("Given two string slice which are both nil", func() {
    16. var a []string = nil
    17. var b []string = nil
    18. Convey("When the comparision is done", func() {
    19. result := StringSliceEqual(a, b)
    20. Convey("Then the result should be true", func() {
    21. So(result, ShouldBeTrue)
    22. })
    23. })
    24. })
    25. })
    26. Convey("TestStringSliceNotEqualIfNotBothNil", t, func() {
    27. Convey("Given two string slice which are both nil", func() {
    28. a := []string(nil)
    29. b := []string{}
    30. Convey("When the comparision is done", func() {
    31. result := StringSliceEqual(a, b)
    32. Convey("Then the result should be false", func() {
    33. So(result, ShouldBeFalse)
    34. })
    35. })
    36. })
    37. })
    38. Convey("TestStringSliceNotEqualIfBothNotNil", t, func() {
    39. Convey("Given two string slice which are both not nil", func() {
    40. a := []string{"hello", "world"}
    41. b := []string{"hello", "goconvey"}
    42. Convey("When the comparision is done", func() {
    43. result := StringSliceEqual(a, b)
    44. Convey("Then the result should be false", func() {
    45. So(result, ShouldBeFalse)
    46. })
    47. })
    48. })
    49. })
    50. }

     2 大坑

    注意!Given层中最好只有一个Then,因为多个Then会导致每执行完一个Then就会再次执行一遍被测试的函数方法,导致多次执行的结果可能并不相同从而导致意料之外的错误(比如上面示例中的“result := StringSliceEqual(a, b)”)。所以如果选择使用GWT的结构,那么就要保证W中只有一个T,最好也要保证G中只有一个W。

    三、自定义断言函数

    断言函数So中第二个参数Assertion类型定义:

    type Assertion func(actual interface{}, expected ...interface{}) string

    返回空字符串表示断言成功,否则就是断言失败了。

    1 自定义断言函数

    所以我们自定义断言函数时也要注意这点,下面是一个参考示例:

    1. func ShouldSummerBeComming(actual interface{}, expected ...interface{}) string {
    2. if actual == "summer" && expected[0] == "comming" {
    3. return ""
    4. } else {
    5. return "summer is not comming!"
    6. }
    7. }

    上述代码中,第一个条件表示断言成功,其它所有情况都是断言失败。

    2 在So中使用自定义的断言函数

    1. func TestSummer(t *testing.T) {
    2. Convey("TestSummer", t, func() {
    3. So("summer", ShouldSummerBeComming, "comming")
    4. So("winter", ShouldSummerBeComming, "comming")
    5. })
    6. }

    测试结果:

    1. === RUN TestSummer
    2. TestSummer ✔✘
    3. Failures:
    4. * /Users/zhangxiaolong/Desktop/D/go-workspace/src/infra/alg/slice_test.go
    5. Line 52:
    6. summer is not comming!
    7. 2 total assertions
    8. --- FAIL: TestSummer (0.00s)
    9. FAIL
    10. exit status 1
    11. FAIL infra/alg 0.006s

  • 相关阅读:
    五分钟上手IoT小程序
    无序标签的使用
    java基于Springboot+vue的好口味水果果蔬销售商城网站
    服务注册与配置一站式管理神器Nacos(二)-- 软件安装及使用技巧
    过滤器(Filter)入门
    使用Triton部署chatglm2-6b模型
    2022年6月1日启动-蓝图功能C++初级编程教学重置计划启动
    开发知识点-Django
    Python tkinter 实现带括号功能的计算器
    开源投票系统源码至尊版带礼物道具 无限多开 盈利模式超丰富
  • 原文地址:https://blog.csdn.net/Hexa_H/article/details/132804639