<p>My coworker just published this about how we test our Go projects: <a href="http://eng.tapjoy.com/blog-list/testing-your-s3-abstraction-for-fun-and-profit-in-go" rel="nofollow">http://eng.tapjoy.com/blog-list/testing-your-s3-abstraction-for-fun-and-profit-in-go</a></p>
<p>I have a Ruby background and have only worked on our Go apps a little, but I found the comparisons super helpful.</p>
<hr/>**评论:**<br/><br/>sethammons: <pre><p>The beauty of testing Go with the stdlib testing package is you don't have to learn something esoteric, you "just write Go code." We had a team with some strong Ruby programmers that started writing Go. They tried so hard, like the author of the post, to make Go tests feel like Ruby. After some experience, they have made the choice to use the stdlib. You have:</p>
<pre><code>Expect(ReadPersonFromS3(mockFetcher)).To(HaveLen(2))
testCall.Times(1)
</code></pre>
<p>When writing a test, I don't want to memorize some strange syntax, odd chaining and parameters. You are not in Ruby, don't pretend to be. Dot imports, strange anonymous functions all over the place. Square peg met round hole. You can avoid all that craziness and have decent test names and, if you like, expand with <code>t.Log()</code> for describing anything:</p>
<pre><code>if len(ReadPersonFromS3(mockFetcher)) != 2{
t.Errorf("got %d, want 2", len(PreadPersonFromS3(mockFetcher))
}
</code></pre>
<p>And I'd argue you likely do not need to test <code>testCall.Times(1)</code>. That is an implementation detail. </p>
<p>As for testing your integration, I've had to test an s3 integration. I needed to make sure that retries worked, that stats were updated, and that the correct logs were created so downstream consumers of the log had a contract. How did I do that? With an interface, of course. And readable, writable, extendable tests. </p>
<pre><code>type Uploader interface {
Upload(file io.Reader, bucket, key string) error
SetUploader(*s3manager.Uploader)
}
</code></pre>
<p>With that, I set the <code>*s3manager.Uploader</code> to nil on my mock/fake struct when I start my test instance of my server. Each test spins up a server, with whatever setup that test needs. I can test any functionality I want now with something like:</p>
<pre><code>type mockUploader struct {
failures int // or any other internal thing I want to track
sync.Mutex
}
func (u *mockUploader) SetUploader(uploader *s3manager.Uploader) {}
func (u *mockUploader) Upload(file io.Reader, bucket, key string) error {
u.Lock()
defer u.Unlock()
// do any kind of set up or checking here.
// return errors or don't. Have logic that says "after the Xth call, return an error. Or have it return an error for a given bucket.
return fmt.Errorf("some s3 error")
}
</code></pre>
<p>Any Go developer can come into this project and start adding value. They don't have to be familiar with Ginkgo or GoMock. The tests don't read like a sentence, and they don't have to. They read like code because that is what they are.
[edit: code formatting]</p></pre>shovelpost: <pre><p><a href="https://media.giphy.com/media/1Z02vuppxP1Pa/giphy.gif" rel="nofollow">Thank you</a>! I couldn't agree more.</p>
<p>I'd like to add that by using the standard library for testing you get rid of a completely unnecessary dependency or maybe even two in this case.</p></pre>upalready: <pre><p>Interesting! Thanks for the detailed reply. I'm definitely curious to talk to my coworkers about the context around the decision to go in this direction for a test suite.</p></pre>mrmylanman: <pre><p>In my experience I have found in general one should almost forget anything learned from Ruby when writing Go. </p>
<p>My first shot at using Go was very frustrating (subconsciously I was treating it like I would Ruby), so this time I forced myself to spend just a little more time learning what the best practices in Go are and as a consequence I found my overall productivity and happiness went way up. Go has an excellent stdlib that should be appreciated more than fought </p></pre>knotdjb: <pre><p>This is actually buried in the <a href="https://golang.org/doc/faq#testing_framework" rel="nofollow">golang faq</a> and seems to be overlooked.</p>
<p><strong>Where is my favorite helper function for testing?</strong></p>
<p>Go's standard testing package makes it easy to write unit tests, but it lacks features provided in other language's testing frameworks such as assertion functions. An earlier section of this document explained why Go doesn't have assertions, and the same arguments apply to the use of assert in tests. Proper error handling means letting other tests run after one has failed, so that the person debugging the failure gets a complete picture of what is wrong. It is more useful for a test to report that isPrime gives the wrong answer for 2, 3, 5, and 7 (or for 2, 4, 8, and 16) than to report that isPrime gives the wrong answer for 2 and therefore no more tests were run. The programmer who triggers the test failure may not be familiar with the code that fails. Time invested writing a good error message now pays off later when the test breaks.</p>
<p>A related point is that testing frameworks tend to develop into mini-languages of their own, with conditionals and controls and printing mechanisms, but Go already has all those capabilities; why recreate them? We'd rather write tests in Go; it's one fewer language to learn and the approach keeps the tests straightforward and easy to understand.</p></pre>TornadoTerran: <pre><p>Reason why BDD framework are there is because some set of problems is hard to express in procedural way. BDD frameworks allows you to create tree-like structure that express chain of events shorter and more readable way than stdlib.</p>
<p>Other story is that Ginkgo and Gomega plays poorly with stdlib and go tools.</p>
<p>I personally suggest to use <a href="http://goconvey.co" rel="nofollow">http://goconvey.co</a> for such case.
Simple (one keyword to remember) and works well with go tools.</p>
<p>It's worth to mention that most of the code should be able to be tested using table tests. Behavioral tests should be just small fraction and not every application needs that in the first place.</p></pre>: <pre><p>[deleted]</p></pre>goomba_gibbon: <pre><p>I think it's always worth asking "do I really need this?" when considering any packages outside the standard library. The post above is very thorough and, as OP suggested, the reasons his co-workers chose this lib are unclear. I'd be interested in hearing them.</p>
<p>I'm sure there are lots of good use-case for this package but there are advantages to keeping to the standard library too.</p>
<p>As developers we know that abstractions can be a good thing but they come at a cost. </p>
<p>We are all just "random pundits on the internet", yourself in included. I found the comment very informative and upvoted accordingly. Thanks also to OP.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传