测试驱动开发-golang-2

2. 变质的对象

测试驱动开发的总体流程如下:

  1. 写一个测试程序。
  2. 让测试程序运行。
  3. 编写合格的代码。

计划清单(to-do list)

当瑞士法郎与美元的兑换率为 2:1 的时候,5 美元 + 10 瑞士法郎 = 10 美元

将 "amount" 定义为私有

5 美元 * 2 = 10 美元

Dollar 类有副作用吗?

钱数必须为整数?

假设对资金乘以 2 倍后再调用一次 dollar.times(3) 方法,我们希望的是以初始金额 5 美元乘以倍数 3,但程序是否会按照我们的意图工作呢?

假设代码如下:

func TestMultiplication(t *testing.T){
	dollar := Dollar{5}
	dollar.times(2)

	got := dollar.amount
	want := 10

	assertEquals(t,got,want)

	dollar.times(3)

	got = dollar.amount
	want = 15

	assertEquals(t,got,want)
}

func assertEquals(t *testing.T, got,want int) {
	if got != want {
		t.Errorf("got %v want %v",got, want)
	}
}

运行结果:

--- FAIL: TestMultiplication (0.00s)
    multiplication_test.go:24: got 30 want 15
FAIL
exit status 1
FAIL    v0.0.0  0.040s

当我们调用 dollar.times(3) 时,希望得到的是 15,但实际得到是 30,意味着再次的调用作用于了上一次调用的 amount。我们希望每次的调用作用于初始的 amount 之上。

?? 小步快跑

实现代码 func(d *Dollar) times(multiplier int) 中的接收者为 Dollar 类型指针,我们将接收者改为 Dollar 类型。

func(d Dollar) times(multiplier int) {
	d.amount *= multiplier
}

先以最小的改动让代测试通过

--- FAIL: TestMultiplication (0.00s)
    multiplication_test.go:24: got 5 want 10
    multiplication_test.go:24: got 5 want 15
FAIL
exit status 1
FAIL    v0.0.0  0.023s

?? 可惜的是,改动并未让测试通过,此时我们有两个选择,将修改的代码恢复为最后一次修改前的状态,或者继续根据现有运行结果查找问题原因并修改。我选择了第二种。

从运行结果看,我们两次调用 dollar.times() 方法,但得到的结果是 5,而不是我们期望的 10 或 15。因为没有结果接收方,所以调用 dollar.times() 方法后产生的结果消失了。

添加变量 amount 接收调用 dollar.times() 方法产生的结果

func TestMultiplication(t *testing.T){
	dollar := Dollar{5}
	amount := dollar.times(2)

	got := amount
	want := 10

	assertEquals(t,got,want)

	dollar.times(3)

	got = dollar.amount
	want = 15

	assertEquals(t,got,want)
}

编译未通过,提示 dollar.times() 方法被用作了值,但实际上方法并未返回值。

# v0.0.0 [v0.0.0.test]
.\multiplication_test.go:7:24: dollar.times(2) used as value
FAIL    v0.0.0 [build failed]

代码中添加返回值

func(d Dollar) times(multiplier int) int {
	return  d.amount * multiplier
}

运行测试通过,但代码中有明显重复代码,需要去除。

?? 代码重构

这里引入"表驱动测试",将测试的输入和期望的结果写在一起组成一个数据表,表中的每条记录都是一个含有输入和期望值的完整测试用例。

dollar := Dollar{5}

amountTests := []struct {
	multiplier int
	want       int
}{
	{multiplier: 2, want: 10},
	{multiplier: 3, want: 15},
}

再次运行测试,测试通过。完成后完整代码如下:

测试代码

func TestMultiplication(t *testing.T) {
	dollar := Dollar{5}

	amountTests := []struct {
		multiplier int
		want       int
	}{
		{multiplier: 2, want: 10},
		{multiplier: 3, want: 15},
	}

	for _, tt := range amountTests {
		got := dollar.times(tt.multiplier)

		if got != tt.want {
			t.Errorf("got %v want %v", got, tt.want)
		}
	}
}

实现代码

type Dollar struct {
	amount int
}

func(d Dollar) times(multiplier int) int {
	return d.amount * multiplier
}

测试驱动开发-golang-2

上一篇:微信公众开发api接口


下一篇:自定义数据