初学TDD

1,717 阅读4分钟

1 TDD学习

1.1 关于TDD

概念

测试驱动开发,英文全称Test-Driven Development,简称TDD,是一种不同于传统软件开发流程的新型的开发方法。 它要求在编写某个功能的代码之前先编写测试代码,然后只编写使测试通过的功能代码,通过测试来推动整个开发的进行。

TDD三原则

  1. 除非为了通过一个单元测试,否则不允许编写任何产品代码。
  2. 在一个单元测试中只允许编写刚好能够导致失败的内容。
  3. 一次只能写通过一项单元测试的产品代码,不能多写。

重构

代码重构(英語:code refactoring)指对软件代码做任何更动以增加可读性或者简化结构而不影响输出结果。

1.2 关于基准测试

什么是基准测试

基准测试是测量一个程序在固定工作负载下的性能。在Go语言中,基准测试函数和普通测试函数写法类似,但是以Benchmark为前缀名,并且带有一个*testing.B类型的参数;*testing.B参数除了提供和*testing.T类似的方法,还有额外一些和性能测量相关的方法。它还提供了一个整数N,用于指定操作执行的循环次数。

基准测试与压力测试

基准测试可以理解为针对系统的一种压力测试。基准测试不关心业务逻辑,更加简单、直接、易于测试,数据可以由工具生成,不要求真实;而压力测试一般考虑业务逻辑,要求真实的数据。

基准测试的作用

对于多数Web应用,整个系统的瓶颈在于数据库;原因很简单:Web应用中的其他因素,例如网络带宽、负载均衡节点、应用服务器(包括CPU、内存、硬盘灯、连接数等)、缓存,都很容易通过水平的扩展(俗称加机器)来实现性能的提高。而对于MySQL,由于数据一致性的要求,无法通过增加机器来分散向数据库写数据带来的压力;虽然可以通过前置缓存(Redis等)、读写分离、分库分表来减轻压力,但是与系统其它组件的水平扩展相比,受到了太多的限制。

而对数据库的基准测试的作用,就是分析在当前的配置下(包括硬件配置、OS、数据库设置等),数据库的性能表现,从而找出MySQL的性能阈值,并根据实际系统的要求调整配置。

1.3 完成“迭代”教程

先写测试

package iteration

import "testing"

func TestRepeat(t *testing.T) {
	repeated := Repeat("a")
	expected := "aaaaa"
    

	if repeated != expected {
		t.Errorf("expected '%q' but got '%q'", expected, repeated)
	}
}

尝试运行测试

使用最少的代码让失败的测试能够运行

package iteration

func Repeat(character string) string {
	return ""
}

结果:

编写可以通过测试的实现

package iteration

func Repeat(character string) string {
	var repeated string
	for i := 0; i < 5; i++ {
		repeated = repeated + character
	}
	return repeated
}

结果:

重构

为了规范性、简洁性、可读性等因素修改代码:

const repeatCount = 5

func Repeat(character string) string {
    var repeated string
    for i := 0; i < repeatCount; i++ {
        repeated += character
    }
    return repeated
}
基准测试
func BenchmarkRepeat(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Repeat("a")
	}
}

值得一提的是goland可以快捷生成测试代码: 结果:

2 完成“迭代”章节练习

修改测试代码,以便调用者可以制定字符重复的次数,然后修复代码

修改测试代码: 然后运行测试: 可见需要修改产品代码以通过单元测试: 测试通过:

写一个ExampleRepeat来完善你的函数文档

可见符合要求。

看一下strings包。找到你认为可能有用的函数,并对它们编写一些测试。

测试Count函数

测试代码:

	s := "go mod init github.com/Winszheng"
	fmt.Printf("test1: %d\n", strings.Count(s, "s"))
	fmt.Printf("test2: %d\n", strings.Count(s, "g"))

结果:

3 选择排序TDD实践报告

先写测试

func TestSelectSort(t *testing.T) {
	initial := []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}
	SelectSort(initial)
	expected := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	for i:=0;i<10;i++ {
		if initial[i]!=expected[i] {
			t.Errorf("expected %v but get %v\n", expected, initial)
		}
	}
}

尝试运行测试

使用最少的代码让失败的测试能够运行

func SelectSort(arr []int) ([]int) {
	return arr
}

结果:

编写可以通过测试的代码

代码:

func SelectSort(arr []int) ([]int) {
	for i := 0; i < len(arr)-1; i++ {
		min := i
		for j := i+1; j < len(arr); j++ {
			if arr[j] < arr[min] {
				min = j
			}
		}
		arr[min], arr[i] = arr[i], arr[min]
	}
	return arr
}

结果:

重构

仿照教程,进行重构:

func SelectSort(arr []int) ([]int) {
	len := len(arr)
	for i := 0; i < len - 1; i++ {
		min := i
		for j := i+1; j < len; j++ {
			if arr[j] < arr[min] {
				min = j
			}
		}
		arr[min], arr[i] = arr[i], arr[min]
	}
	return arr
}

基准测试

func Benchmark(b *testing.B) {
	for i := 0; i < b.N; i++ {
		initial := []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}
		SelectSort(initial)
	}
}

运行基准测试:

4 参考

Test-Driven Development(TDD) in Go

基准测试

如何撰写godoc