问题:
你被要求编写一个叫做 WebsiteRacer
的函数,用来对比请求两个 URL 来「比赛」,并返回先响应的 URL。如果两个 URL 在 10 秒内都未返回结果,那么应该返回一个 error
。
实现这个功能我们需要用到
-
net/http
用来调用 HTTP 请求
-
net/http/httptest
用来测试这些请求
-
Go 程(goroutines)
-
select
先写测试
我们从最幼稚的做法开头把事情开展起来。
func TestRacer(t *testing.T) { slowURL := "http://www.facebook.com" fastURL := "http://www.quii.co.uk" want := fastURL got := Racer(slowURL, fastURL) if got != want { t.Errorf("got '%s', want '%s'", got, want) } }
我们知道这样不完美并且有问题,但这样可以把事情开展起来。重要的是,不要徘徊在第一次就想把事情做到完美。
尝试运行测试
./racer_test.go:14:9: undefined: Racer
为测试的运行编写最少量的代码,并检查失败测试的输出
func Racer(a, b string) (winner string) { return }
racer_test.go:25: got '', want 'http://www.quii.co.uk'
编写足够的代码使程序通过
func Racer(a, b string) (winner string) { startA := time.Now() http.Get(a) aDuration := time.Since(startA) startB := time.Now() http.Get(b) bDuration := time.Since(startB) if aDuration < bDuration { return a } return b }
对每个 URL:
-
1.我们用
time.Now()
来记录请求URL
前的时间。
-
2.然后用
http.Get
来请求URL
的内容。这个函数返回一个http.Response
和一个error
,但目前我们不关心它们的值。
-
3.
time.Since
获取开始时间并返回一个time.Duration
时间差。
我们完成这些后就可以通过对比请求耗时来找出最快的了。
问题
这可能会让你的测试通过,也可能不会。问题是我们通过访问真实网站来测试我们的逻辑。
使用 HTTP 测试代码非常常见,Go 标准库有这类工具可以帮助测试。
在前两章模拟和依赖注入章节中,我们讲到了理想情况下如何不依赖外部服务来进行测试,因为它们可能
-
速度慢
-
不可靠
- 无法进行边界条件测试
在标准库中有一个
net/http/httptest
包,它可以让你轻易建立一个 HTTP 模拟服务器(mock HTTP server)。我们改为使用模拟测试,这样我们就可以控制可靠的服务器来测试了。