我正在通过编写一个小型个人项目来学习Go。即使很小,我还是决定从头开始进行严格的单元测试,以学习Go的良好习惯。
琐碎的单元测试都很好而且花哨的,但是我现在对依赖项感到困惑;我希望能够用模拟函数替换一些函数调用。这是我的代码片段:
func get_page(url string) string {
get_dl_slot(url)
defer free_dl_slot(url)
resp, err := http.Get(url)
if err != nil { return "" }
defer resp.Body.Close()
contents, err := ioutil.ReadAll(resp.Body)
if err != nil { return "" }
return string(contents)
}
func downloader() {
dl_slots = make(chan bool, DL_SLOT_AMOUNT) // Init the download slot semaphore
content := get_page(BASE_URL)
links_regexp := regexp.MustCompile(LIST_LINK_REGEXP)
matches := links_regexp.FindAllStringSubmatch(content, -1)
for _, match := range matches{
go serie_dl(match[1], match[2])
}
}
我希望能够测试downloader()而不实际通过http获取页面-
即通过模拟get_page(更容易使用,因为它仅将页面内容作为字符串返回)或http.Get()。
我找到了这个线程:https :
//groups.google.com/forum/#!topic/golang- nuts/
6AN1E2CJOxI,这似乎与一个类似的问题有关。朱利安·菲利普斯(Julian
Phillips)提出了他的图书馆Withmock(http://github.com/qur/withmock)作为解决方案,但我无法使其正常工作。老实说,这是我的测试代码的相关部分,对我来说,这基本上是对货物的崇拜代码:
import (
"testing"
"net/http" // mock
"code.google.com/p/gomock"
)
...
func TestDownloader (t *testing.T) {
ctrl := gomock.NewController()
defer ctrl.Finish()
http.MOCK().SetController(ctrl)
http.EXPECT().Get(BASE_URL)
downloader()
// The rest to be written
}
测试输出如下:
ERROR: Failed to install '_et/http': exit status 1
output:
can't load package: package _et/http: found packages http (chunked.go) and main (main_mock.go) in /var/folders/z9/ql_yn5h550s6shtb9c5sggj40000gn/T/withmock570825607/path/src/_et/http
Withmock是否可以解决我的测试问题?我应该怎么做才能使其正常工作?
感谢您练习良好的测试!:)
就我个人而言,我不使用gomock
(或任何模拟框架;没有它,Go中的模拟非常容易)。我要么将依赖项downloader()
作为参数传递给函数,要么downloader()
在类型上创建方法,并且该类型可以容纳该get_page
依赖项:
type PageGetter func(url string) string
func downloader(pageGetterFunc PageGetter) {
// ...
content := pageGetterFunc(BASE_URL)
// ...
}
主要:
func get_page(url string) string { /* ... */ }
func main() {
downloader(get_page)
}
测试:
func mock_get_page(url string) string {
// mock your 'get_page()' function here
}
func TestDownloader(t *testing.T) {
downloader(mock_get_page)
}
download()
一种类型的方法Downloader
:如果您不想将依赖项作为参数传递,则还可以使get_page()
一个类型成为成员,并使其download()
成为该类型的方法,然后可以使用get_page
:
type PageGetter func(url string) string
type Downloader struct {
get_page PageGetter
}
func NewDownloader(pg PageGetter) *Downloader {
return &Downloader{get_page: pg}
}
func (d *Downloader) download() {
//...
content := d.get_page(BASE_URL)
//...
}
主要:
func get_page(url string) string { /* ... */ }
func main() {
d := NewDownloader(get_page)
d.download()
}
测试:
func mock_get_page(url string) string {
// mock your 'get_page()' function here
}
func TestDownloader() {
d := NewDownloader(mock_get_page)
d.download()
}
问题内容: 我正在尝试为向Web服务发出请求的程序包编写测试。我可能由于缺乏对TLS的了解而遇到问题。 目前,我的测试看起来像这样: 我的程序包具有一个要查询的Web服务基址的程序包变量(我希望它是一个常量。)。这是一个https URL。我在上面创建的测试服务器是纯HTTP,没有TLS。 默认情况下,我的测试失败,并显示错误“ tls:第一条记录看起来不像TLS握手”。 为了使它起作用,我的测试
问题内容: 在Go中,TCP连接(net.Conn)是io.ReadWriteCloser。我想通过模拟TCP连接来测试我的网络代码。我有两个要求: 要读取的数据存储在字符串中 每当写入数据时,我都希望将其存储在某种缓冲区中,以便以后使用 是否有数据结构或简单的方法? 问题答案: 为什么不使用?它是一种并且具有获取存储数据的方法。如果需要将其设置为,则可以定义自己的类型: 并定义一个方法:
问题内容: 如何在MySQL中的此表上做滞后处理以打印引号中的差异,例如: 问题答案: 这是我最喜欢的MySQL hack。 这是模拟滞后函数的方式: 保存上一行报价的值。对于第一行,@ quot是-1。 保留当前行的报价的值。 笔记: 子句在这里很重要,就像在常规窗口函数中一样。 您可能还想使用lag 来确保计算相同引号的差异。 您也可以以相同的方式实现行计数器 与该方案相比,与使用聚合函数,存
问题内容: 有没有一种简单的方法可以在进行测试时模拟Hashicorp保险库? 我在Go中创建了一个可访问保险柜的服务,并希望为其创建适当的测试。 我没有找到我喜欢的简单解决方案(例如python中的moto)。我还尝试在docker中以dev模式使用Vault(采用系统测试路线),但我无法通过API写入文件。想法? 问题答案: 有没有一种简单的方法可以在Go测试中模拟HashiCorp Vaul
问题内容: 情况: 我想从控制台获取密码输入- 而不回显用户键入的内容 。有什么可以和Go中的功能媲美吗? 我试过的 我尝试使用,但它回显了键入的内容。 问题答案: 您可以通过执行以下操作来关闭回显,然后在读取密码后将其重新打开
问题内容: 我试过了 但这会引发语法错误。我也尝试过像这样修补 有什么办法吗? 问题答案: 是python 2.x中的关键字,将其用作属性会引发SyntaxError。您可以通过在文件开头使用来避免这种情况。 注意:您不能简单地使用,因为除非禁用该语句,否则不会调用您修改的print函数。 编辑:您还需要在每个要使用修改后功能的文件中使用它,否则它将被该语句掩盖。