我对依赖感到困惑。我希望能够用模拟函数调用替换一些函数调用。这是我的代码片段:
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().
downloader()
get_page
http.Get()
我发现这个线程似乎是关于一个类似的问题。Julian Phillips 展示了他的库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 }
测试输出如下:
错误:无法安装 ‘_et/http’:退出状态 1 输出:无法加载包:包 _et/http:在 /var/folders/z9/中找到包 http (chunked.go) 和 main (main_mock.go) ql_yn5h550s6shtb9c5sggj40000gn/T/withmock570825607/path/src/_et/http
Withmock 可以解决我的测试问题吗?我应该怎么做才能让它工作?
就个人而言,我不使用gomock(或任何模拟框架;没有它,Go 中的模拟非常容易)。我要么将依赖项downloader()作为参数传递给函数,要么downloader()在类型上创建一个方法,并且该类型可以保存get_page依赖项:
gomock
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() }