sc_homework2

PART 1

参考网站Learn Go with tests

完成该教程中“迭代”章节的练习,理解TDD、重构、测试、基准测试等概念。

在 Go 中 for 用来循环和迭代,Go 语言没有 while,do,until 这几个关键字,只能使用 for。

概念理解

TDD

TDD,测试驱动开发(Test-Driven Development),即测试在先、编码在后的开发实践。TDD是敏捷开发中的一项核心实践和技术,也是一种设计方法论,其原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码,其实施手段是单元测试。TDD虽是敏捷方法的核心实践,但不只适用于XP(Extreme Programming),同样可以适用于其他开发方法和过程。 总的来说,其核心思想就是通过测试来推动整个开发的进行,但测试驱动开发并不只是单纯的测试工作,而是把需求分析,设计,质量控制量化的过程。TDD使开发人员对所做的设计或所写的代码有足够的信心,同时也有勇气进行设计或代码的快速重构,有利于快速迭代、持续交付。

在Go语言的工作环境中,TDD可以简单理解为:
对于某个要实现某种功能的函数或库,我们在实现那个函数或库之前,先根据对于某些输入应该产生什么预期结果来编写测试函数。以测试用例驱动功能函数的实现。

TDD的具体实施过程可以分为两个层次:

  1. 在代码层次,在编码之前写测试代码,可以称为单元测试驱动开发(Unit Test Driven Development,UTDD);
    测试代码的作用:在被测代码发生改动后,执行单元测试用例即可验证本次改动是否对函数原有功能造成影响,是未来函数重构的信心保证。
  2. 在业务层次,在需求分析时就确定需求(如用户故事)的验收标准,即验收测试驱动开发(Acceptance Test Driven Development,ATDD)。

测试

首先先写测试并尝试运行测试:在没有写主要实现的算法之前,先写好测试的文件,测试文件中函数的参数应该是固定的。

然后使用最少的代码来让测试跑起来:为了检测测试代码的编写是否正确,需要先写一个简要的被测试的文件,只需让代码可编译,以检查测试用例能否通过。

最后把代码补全,使得其能够通过测试:若测试文件编写没有问题,则补全被测试文件的代码,补全后,在命令行中输入 go test 命令即可进行测试,或者直接编译运行测试文件,也可以进行测试,其中命令行测试时,加入不同的参数,会测试不同的内容。

重构

一般的文件都有重构的习惯,即假如原有的函数只有两个参数,重构后可以使得参数增加或者减少,然后重新进行测试。重构的前提就是测试就绪(testing is ready),在这样的前提下,重构的风险就很低,否则就有比较高的风险。

基准测试

基准测试(benchmarks)是测试运行代码需要多少的时间,其编写是Go语言的另一个一级特性,与编写测试十分相似。基准测试会有固定的名字,并且有特定的参数,其中 b.N 代表使程序运行多少次,最后在命令行中执行命令 go test -bench=. (不同的操作系统命令可能会有些许区别)。

测试

先写测试

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)    
	}
}

尝试运行测试

./repeat_test.go:6:14: undefined: Repeat

先使用最少的代码来让失败的测试先跑起来

现在只需让代码可编译,这样你就可以检查测试用例能否通过。

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

现在已经掌握了足够的 Go 知识来给一些基本的问题编写测试,这意味着可以放心的处理生产环境的代码,并知道它的行为会如你所愿。

repeat_test.go:10: expected 'aaaaa' but got ''

把代码补充完整,使得它能够通过测试

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

与其它语言如 C,Java 或 JavaScript 不同,在 Go 中 for 语句前导条件部分并没有圆括号,而且大括号 { } 是必须的。你可能会好奇下面这行。

var repeated string

我们目前都是使用 := 来声明和初始化变量。然后 := 只是两个步骤的简写。这里我们使用显式的版本来声明一个 string 类型的变量。我们还可以使用 var 来声明函数,稍后我们将看到这一点。
运行测试应该是通过的。

重构

现在是时候重构并引入另一个构造(construct)+= 赋值运算符。

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

+= 是自增赋值运算符(Add AND assignment operator),它把运算符右边的值加到左边并重新赋值给左边。它在其它类型也可以使用,比如整数类型。

基准测试

在 Go 中编写基准测试(benchmarks)是该语言的另一个一级特性,它与编写测试非常相似。

func BenchmarkRepeat(b *testing.B) {    
	for i := 0; i < b.N; i++ {        
		Repeat("a")    
	}
}

你会看到上面的代码和写测试差不多。
testing.B 可使你访问隐性命名(cryptically named)b.N。
基准测试运行时,代码会运行 b.N 次,并测量需要多长时间。
代码运行的次数不会对你产生影响,测试框架会选择一个它所认为的最佳值,以便让你获得更合理的结果。
用 go test -bench=. 来运行基准测试。 (如果在 Windows Powershell 环境下使用 go test -bench=".")

goos: darwin
goarch: amd64
pkg: github.com/quii/learn-go-with-tests/for/v4
10000000           136 ns/op
PASS

以上结果说明运行一次这个函数需要 136 纳秒(在我的电脑上)。这挺不错的,为了测试它运行了 10000000 次。注意:基准测试默认是顺序运行的。

练习

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

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

3. 看一下 strings 包。找到你认为可能有用的函数,并对它们编写一些测试。投入时间学习标准库会慢慢得到回报。

PART 2

自己选择一个算法如“快排”,模仿教程内容结构,写一个Go语言某算法实现TDD实践报告。

快排思路

快速排序算法(Quicksort)的主要步骤为:

  1. 在数组中设定一个分界值,该分界值将数组分成了左右两部分。
  2. 将大于或等于分界值的数据移动到数组右边,小于分界值的数据移动到数组的左边,从而使左侧部分中的数据都小于或等于分界值,而右侧部分中的数据都大于或等于分界值。
  3. 左侧和右侧的数据组成的数组可以再同样独立地进行排序:对于左侧数组的数据,又可以取一个分界值,将该数组分成左右两部分,在左侧放置较小值,在右侧放置较大值;而右侧的数组数据也做类似的处理。
  4. 重复上述过程,产生递归。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也完成了。

Go语言测试

先写测试
最少代码运行测试
代码补全测试
重构
基准测试

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值