工程开发概念汇总(一) | 青训营笔记

160 阅读2分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第4篇笔记

单元测试

什么是单元测试?

  • 首先它是测试==》检测代码正确性
  • 其次它是个单元==》粒度最小

  • 例如,实现一个加法函数:

  • 我们的几个单元测试可以这样进行:

    // add.go​
    package main​
    
    func Add(x, y int) int {​
       return x + y​
    }
    

// add_test.go​
package main​

func TestAdd1(t *testing.T) {​
   x := 1​
   y := 1​
   want := 2​
   got := Add(x, y)​
   if got != want {​
      t.Errorf("%d+%d=%d, but %d expected", x, y, got, want)​
   }​
}

为什么我们需要单元测试?

  • 万一有bug就完蛋了,测边界值防止意外发生,保证正确性
  • 万一你的函数要被重构了,新的函数怎么证明它的正确性,怎么debug
  • 钝角

哪里需要单元测试?

  • 我就加了一个if,怎么就出bug了(复杂+容易出错)
  • 这个库整个公司都在使用,出问题就n+1了(基础代码&公共代码)
  • 这个广告计费模块太重要了(重要性)
  • 这个需求老变,每次一变我就要改好多单测【这种情况不推荐写单测,因为一改需求就要推倒重来】(基础&底层)

什么时候写单元测试

  • 在写代码之前把所有的测试情况想好,测试点就过了就是写好了(难度较高,但是比较流行(TDD))(编码前)
  • 写一段,来一个单测,再写一段,再来一个单测(编码中)
  • 最后做一个全范围覆盖,补上所有的测试(编码后,大多数人会做的选择)

如何写单元测试

  • 在当前package下新建文件add.go,并实现Add函数
// add.go
package main

func Add(x, y int) int {
   return x + y
}

  • 我们想测试Add函数,那么我们需要在add.go的package下创建add_test.go,并实现逻辑
// add_test.go​
package main​

func TestAdd1(t *testing.T) {​
   x := 1​
   y := 1​
   want := 2​
   got := Add(x, y)​
   if got != want {​
      t.Errorf("%d+%d=%d, but %d expected", x, y, got, want)​
   }​
}

  • 如果我们想并发跑很多case:
// add_test.go​
func TestAdd2(t *testing.T) {​
   type tCase struct {​
      x        int​
      y        int​
      expected int​
   }​
   cases := make([]*tCase, 0, 0)​

   // test1​
   cases = append(cases, &tCase{​
      x:        1,​
      y:        -1,​
      expected: 0,​
   })​

   // test2​
   cases = append(cases, &tCase{​
      x:        1,​
      y:        2,​
      expected: 3,​
   })​
   for i, c := range cases {​
      t.Run(fmt.Sprintf("case%d", i), func(t *testing.T) {​
         got := Add(c.x, c.y)​
         if got != c.expected {​
            t.Errorf("%d+%d expected %d, but %d got", c.x, c.y, c.expected, got)​
         }​
      })​
   }​
}

  • mock必不可少
// add_test.go​
func init() {​
   rand.Seed(time.Now().UnixNano())​
}​

func AddWithRandom(x, y int) int {​
   return x + y + rand.Int()​
}

  • mock random.Int()
func TestAddWithRandom(t *testing.T) {
   monkey.Patch(rand.Int, func() int { return 0 })
   x := 1
   y := 1
   expected := 2
   got := AddWithRandom(x, y)
   if got != expected {
      t.Errorf("%d+%d expected %d, but %d got", x, y, expected, got)
   }
}

  • 基准测试
func BenchmarkAdd(b *testing.B) {​
   for i := 0; i < b.N; i++ {​
      for j := 0; j < 1e9; j++ {​
         Add(i, i+1)​
      }​
   }​
}​

func BenchmarkMul(b *testing.B) {​
   for i := 0; i < b.N; i++ {​
      for j := 0; j < 1e9; j++ {​
         Mul(i, i+1)​
      }​
   }​
}