<p>As the title suggests I'm using <a href="https://golang.org/pkg/net/http/httptest/" rel="nofollow">http/httptest.Server</a> to test a small app I am writing to help me learn Go.</p>
<p>The project can be found here: <a href="https://github.com/tjheslin1/YAHNCrawler" rel="nofollow">YAHNCrawler</a>. It prints the story information of the top stories on Hacker News. I'm striving towards concurrency here.</p>
<p>My problem, getting the testServer to handle different url paths:</p>
<p>my query code:</p>
<pre><code>// query performs a HTTP: GET request to the specified url.
// Storing the response's body in the `result`.
// query expects the provided `result` to conform to the query's repsonse body.
func query(url string, result interface{}) *interface{} {
resp, err := http.Get(url)
check(err)
body, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
check(err)
unmarshalErr := json.Unmarshal(body, result)
check(unmarshalErr)
return &result
}
</code></pre>
<p>The issue is this method is called twice. Once to get a list of ids of the top stories, the next call queries the information of a story by one of these ids using a different url path.</p>
<p>I have tests for each call but I want to do a full end-to-end test of the exported function <code>CrawlTopStories</code>. </p>
<p>my test:</p>
<pre><code>func TestCrawlTopStories(t *testing.T) {
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, `[ 14223020 ]`)
}))
defer testServer.Close()
CrawlTopStories(testServer.URL)
// TODO fail test if not passed
}
</code></pre>
<p>Above in <code>TestCrawlTopStories</code> I have set up the test server to respond with the id of a single story, necessary for the first call. But I need a separate handler to support the second call to "/story/{id}".</p>
<p>Is there a solution where I can reuse the same testServer? Reading httptest.Server.go hasn't shed any light on this issue, maybe I need to look deeper.</p>
<p>Once I have this solved I would like to address this code:</p>
<pre><code>storyChan := make(chan *Story, topStoryCount)
go func(storyCh chan<- *Story) {
for _, topStoryID := range *topStoryIDs {
storyCh <- queryStory("https://hacker-news.firebaseio.com/v0/item/" + strconv.Itoa(topStoryID) + ".json?print=pretty")
time.Sleep(500 * time.Millisecond)
}
close(storyChan)
}(storyChan)
....
</code></pre>
<p>Ideally I could make each call, concurrently in a separate goroutine, but then I wouldn't be able to safely close the channel before ranging over it. As I will be querying 500 stories, is there a point in trying to improve this?</p>
<p>Many thanks</p>
<hr/>**评论:**<br/><br/>HectorJ: <pre><p>So you need routing for your <code>httptest</code> server.</p>
<p>Well it's exactly the same as routing for a <code>http</code> server.</p>
<p>For a quick solution, you can use <a href="https://golang.org/pkg/net/http/#ServeMux" rel="nofollow"><code>http.ServeMux</code></a>. Build one, and pass that to <code>httptest.NewServer</code> instead of your <code>http.HandlerFunc</code>.</p>
<p>Ultimately, if your test data are 100% static, I think you would be better off storing them in files and using a <a href="https://golang.org/pkg/net/http/#FileServer" rel="nofollow"><code>http.FileServer</code></a></p></pre>tommy144p: <pre><p>Thanks! I'll look into this. A problem I've found with Go is that due to its implicit inheritance, it's hard to find implementations of interfaces and therefore would likely not have found ServeMux for a long time. Do you know of any method of finding existing implementations?</p></pre>shovelpost: <pre><p><a href="https://docs.google.com/document/d/1_Y9xCEMj5S-7rv2ooHpZNH15JgRT5iM742gJkw5LtmQ/edit" rel="nofollow">Go Guru</a></p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传