mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-08-09 16:42:26 +00:00
make
This commit is contained in:
@@ -1,47 +1,60 @@
|
||||
### 11.2.4. 擴展測試包
|
||||
|
||||
考虑下这两个包: net/url 包, 提供了 URL 解析的功能; net/http 包, 提供了web服务和HTTP客户端的功能. 如我们所料, 上层的 net/http 包依赖下层的 net/url 包. 然后, net/url 包中的一个测试是演示不同URL和HTTP客户端的交互行为. 也就是说, 一个下层包的测试代码导入了上层的包.
|
||||
考慮下這兩個包: net/url 包, 提供了 URL 解析的功能; net/http 包, 提供了web服務和HTTP客戶端的功能. 如我們所料, 上層的 net/http 包依賴下層的 net/url 包. 然後, net/url 包中的一個測試是演示不衕URL和HTTP客戶端的交互行為. 也就是説, 一個下層包的測試代碼導入了上層的包.
|
||||
|
||||

|
||||
|
||||
这样的行为在 net/url 包的测试代码中会导致包的循环依赖, 正如 图11.1中向上箭头所示, 同时正如我们在 10.1节所说, Go语言规范是禁止包的循环依赖的.
|
||||
這樣的行為在 net/url 包的測試代碼中會導緻包的循環依賴, 正如 圖11.1中嚮上箭頭所示, 衕時正如我們在 10.1節所説, Go語言規範是禁止包的循環依賴的.
|
||||
|
||||
我们可以通过测试扩展包的方式解决循环依赖的问题, 也就是在 net/url 包所在的目录声明一个 url_test 测试扩展包. 其中测试扩展包名的 `_test` 后缀告诉 go test 工具它应该建立一个额外的包来运行测试. 我们将这个扩展测试包的导入路径视作是 net/url_test 会更容易理解, 但实际上它并不能被其他任何包导入.
|
||||
我們可以通過測試擴展包的方式解決循環依賴的問題, 也就是在 net/url 包所在的目録聲明一個 url_test 測試擴展包. 其中測試擴展包名的 `_test` 後綴告訴 go test 工具它應該建立一個額外的包來運行測試. 我們將這個擴展測試包的導入路徑視作是 net/url_test 會更容易理解, 但實際上它並不能被其他任何包導入.
|
||||
|
||||
因为测试扩展包是一个独立的包, 因此可以导入测试代码依赖的其他的辅助包; 包内的测试代码可能无法做到. 在设计层面, 测试扩展包是在所以它依赖的包的上层, 正如 图11.2所示.
|
||||
因為測試擴展包是一個獨立的包, 因此可以導入測試代碼依賴的其他的輔助包; 包內的測試代碼可能無法做到. 在設計層麪, 測試擴展包是在所以它依賴的包的上層, 正如 圖11.2所示.
|
||||
|
||||

|
||||
|
||||
通过回避循环导入依赖, 扩展测试包可以更灵活的测试, 特别是集成测试(需要测试多个组件之间的交互), 可以像普通应用程序那样自由地导入其他包.
|
||||
通過迴避循環導入依賴, 擴展測試包可以更靈活的測試, 特彆是集成測試(需要測試多個組件之間的交互), 可以像普通應用程序那樣自由地導入其他包.
|
||||
|
||||
我们可以用 go list 工具查看包对应目录中哪些Go源文件是产品代码, 哪些是包内测试, 还哪些测试扩展包. 我们以 fmt 包作为一个例子. GoFiles 表示产品代码对应的Go源文件列表; 也就是 go build 命令要编译的部分:
|
||||
我們可以用 go list 工具査看包對應目録中哪些Go源文件是產品代碼, 哪些是包內測試, 還哪些測試擴展包. 我們以 fmt 包作為一個例子. GoFiles 錶示產品代碼對應的Go源文件列錶; 也就是 go build 命令要編譯的部分:
|
||||
|
||||
{% raw %}
|
||||
|
||||
```
|
||||
$ go list -f={{.GoFiles}} fmt
|
||||
[doc.go format.go print.go scan.go]
|
||||
```
|
||||
|
||||
TestGoFiles 表示的是 fmt 包内部测试测试代码, 以 _test.go 为后缀文件名, 不过只在测试时被构建:
|
||||
{% endraw %}
|
||||
|
||||
TestGoFiles 錶示的是 fmt 包內部測試測試代碼, 以 _test.go 為後綴文件名, 不過隻在測試時被構建:
|
||||
|
||||
{% raw %}
|
||||
|
||||
```
|
||||
$ go list -f={{.TestGoFiles}} fmt
|
||||
[export_test.go]
|
||||
```
|
||||
|
||||
包的测试代码通常都在这些文件中, 不过 fmt 包并非如此; 稍后我们再解释 export_test.go 文件的作用.
|
||||
{% endraw %}
|
||||
|
||||
XTestGoFiles 表示的是属于测试扩展包的测试代码, 也就是 fmt_test 包, 因此它们必须先导入 fmt 包. 同样, 这些文件也只是在测试时被构建运行:
|
||||
包的測試代碼通常都在這些文件中, 不過 fmt 包並非如此; 稍後我們再解釋 export_test.go 文件的作用.
|
||||
|
||||
XTestGoFiles 錶示的是屬於測試擴展包的測試代碼, 也就是 fmt_test 包, 因此它們必鬚先導入 fmt 包. 衕樣, 這些文件也隻是在測試時被構建運行:
|
||||
|
||||
|
||||
{% raw %}
|
||||
|
||||
```
|
||||
$ go list -f={{.XTestGoFiles}} fmt
|
||||
[fmt_test.go scan_test.go stringer_test.go]
|
||||
```
|
||||
|
||||
有时候测试扩展包需要访问被测试包内部的代码, 例如在一个为了避免循环导入而被独立到外部测试扩展包的白盒测试. 在这种情况下, 我们可以通过一些技巧解决: 我们在包内的一个 _test.go 文件中导出一个内部的实现给测试扩展包. 因为这些代码只有在测试时才需要, 因此一般放在 export_test.go 文件中.
|
||||
{% endraw %}
|
||||
|
||||
例如, fmt 包的 fmt.Scanf 需要 unicode.IsSpace 函数提供的功能. 但是为了避免太多的依赖, fmt 包并没有导入包含巨大表格数据的 unicode 包; 相反fmt包有一个叫 isSpace 内部的简易实现.
|
||||
有時候測試擴展包需要訪問被測試包內部的代碼, 例如在一個為了避免循環導入而被獨立到外部測試擴展包的白盒測試. 在這種情況下, 我們可以通過一些技巧解決: 我們在包內的一個 _test.go 文件中導齣一個內部的實現給測試擴展包. 因為這些代碼隻有在測試時纔需要, 因此一般放在 export_test.go 文件中.
|
||||
|
||||
为了确保 fmt.isSpace 和 unicode.IsSpace 函数的行为一致, fmt 包谨慎地包含了一个测试. 是一个在测试扩展包内的测试, 因此是无法直接访问到 isSpace 内部函数的, 因此 fmt 通过一个秘密出口导出了 isSpace 函数. export_test.go 文件就是专门用于测试扩展包的秘密出口.
|
||||
例如, fmt 包的 fmt.Scanf 需要 unicode.IsSpace 函數提供的功能. 但是為了避免太多的依賴, fmt 包並沒有導入包含鉅大錶格數據的 unicode 包; 相反fmt包有一個叫 isSpace 內部的簡易實現.
|
||||
|
||||
為了確保 fmt.isSpace 和 unicode.IsSpace 函數的行為一緻, fmt 包謹慎地包含了一個測試. 是一個在測試擴展包內的測試, 因此是無法直接訪問到 isSpace 內部函數的, 因此 fmt 通過一個祕密齣口導齣了 isSpace 函數. export_test.go 文件就是專門用於測試擴展包的祕密齣口.
|
||||
|
||||
```Go
|
||||
package fmt
|
||||
@@ -49,5 +62,5 @@ package fmt
|
||||
var IsSpace = isSpace
|
||||
```
|
||||
|
||||
这个测试文件并没有定义测试代码; 它只是通过 fmt.IsSpace 简单导出了内部的 isSpace 函数, 提供给测试扩展包使用. 这个技巧可以广泛用于位于测试扩展包的白盒测试.
|
||||
這個測試文件並沒有定義測試代碼; 它隻是通過 fmt.IsSpace 簡單導齣了內部的 isSpace 函數, 提供給測試擴展包使用. 這個技巧可以廣汎用於位於測試擴展包的白盒測試.
|
||||
|
||||
|
Reference in New Issue
Block a user