patterngoCritical
Mock functions in Go
Viewed 0 times
functionsmockstackoverflow
Problem
I'm puzzled with dependencies. I want to be able to replace some function calls with mock ones. Here's a snippet of my code:
I'd like to be able to test
I found this thread which seems to be about a similar problem. Julian Phillips presents his library, Withmock as a solution, but I'm unable to get it to work. Here's the relevant parts of my testing code, which is largely cargo cult code to me, to be honest:
The test output is following:
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
Is the Withmock a solution to my testing problem? What should I do to get it to work?
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])
}
}I'd like to be able to test
downloader() without actually getting a page through http - i.e. by mocking either get_page (easier since it returns just the page content as a string) or http.Get().I found this thread which seems to be about a similar problem. Julian Phillips presents his library, Withmock as a solution, but I'm unable to get it to work. Here's the relevant parts of my testing code, which is largely cargo cult code to me, to be honest:
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
}The test output is following:
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
Is the Withmock a solution to my testing problem? What should I do to get it to work?
Solution
Personally, I don't use
Method 1: Pass
Main:
Test:
Method2: Make
If you don't want to pass the dependency as a parameter, you could also make
Main:
Test:
gomock (or any mocking framework for that matter; mocking in Go is very easy without it). I would either pass a dependency to the downloader() function as a parameter, or I would make downloader() a method on a type, and the type can hold the get_page dependency:Method 1: Pass
get_page() as a parameter of downloader()type PageGetter func(url string) string
func downloader(pageGetterFunc PageGetter) {
// ...
content := pageGetterFunc(BASE_URL)
// ...
}Main:
func get_page(url string) string { /* ... */ }
func main() {
downloader(get_page)
}Test:
func mock_get_page(url string) string {
// mock your 'get_page()' function here
}
func TestDownloader(t *testing.T) {
downloader(mock_get_page)
}Method2: Make
download() a method of a type Downloader:If you don't want to pass the dependency as a parameter, you could also make
get_page() a member of a type, and make download() a method of that type, which can then use 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)
//...
}Main:
func get_page(url string) string { /* ... */ }
func main() {
d := NewDownloader(get_page)
d.download()
}Test:
func mock_get_page(url string) string {
// mock your 'get_page()' function here
}
func TestDownloader() {
d := NewDownloader(mock_get_page)
d.download()
}Code Snippets
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)
}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()
}Context
Stack Overflow Q#19167970, score: 264
Revisions (0)
No revisions yet.