Hey all, this is the author of Ginkgo & Gomega. I'm excited to see all this thoughtful conversation and figured I'd chime in with a response to keep the conversation going. (Apologies for the long post!)<p>- Godoc documentation is coming soon. Godoc is great for API-style documentation but not particularly appropriate for tutorial/structured/narrative-style documentation. Think golang.org/pkg vs golang.org/doc. I wanted to write the /doc first as I believe it to be more valuable for beginners and is often overlooked by the go community. /pkg is coming soon (a few days) and is much easier to write.<p>- @buro9: Golang is BDD-style in the same way that Cedar and Jasmine are BDD-style. This is not Cucumber (way too much DSL for me!) With that said, asynchronous testing support is baked right into Ginkgo and Gomega so the API-testing that you'd like would be easily expressed in Ginkgo and Gomega.<p>- Assertions that I have fundamentally misunderstood Golang or the distinction between dynamic and static typed languages are interesting and I'd like to address some of them.<p>BDD-style testing need not be limited to dynamically-typed language. Yes dynamically-typed languages need far more comprehensive test coverage to make up for the missing compiler. That's why I tend to prefer statically-typed languages. To me BDD-style (vs the XUnit style) isn't primarily about addressing these deficiencies in dynamic languages -- it's about <i>expressiveness</i>.<p>To that end, I think that BDD and Golang go hand in hand. Let me explain. BDD is exceptionally good at describing the behavior of branching code. Golang is filled with branching code that needs to be described in test. Here's a classic example in pseudo-go:<p><pre><code> func DoSomethingAwesome(dependencyA DepA, dependencyB DepB) awesome Awesome, err error {
stuffA, err := dependencyA.Gimme()
if err != nil {
return Awesome{}, err
}
stuffB, err := dependencyB.Gimme()
if err != nil {
return Awesome{}, err
}
....
return awesome, nil
}
</code></pre>
With Ginkgo you can cover these branches expressively:<p><pre><code> Describe("Doing something Awesome", func() {
BeforeEach(...) //common happy case setup
Context("When all is well", func() {
It("should be awesome", ...)
})
Context("When dependencyA fails", func() {
BeforeEach(...) //set dependencA up for failure
It("should return a zero Awesome", func() {
...
Expect(awesome).To(BeZero())
})
It("should error", func() {
...
Expect(err).To(HaveOccured())
})
})
Context("When dependencyB fails", func() {
//etc...
})
})
</code></pre>
Compare this to the XUnit style:<p><pre><code> func TestDoingSomethingAwesomeWhenAllIsWell() {
//setup
//some sort of assertion
}
func TestDoingSomethingAwesomeWhenDependencyAFails() {
//setup + tweak
//some sort of assertion that awesome is zero
//some sort of assertion about err
}
func TestDoingSomethingAwesomeWhenDependencyBFails() {
//setup + tweak
//some sort of assertion that awesome is zero
//some sort of assertion about err
}
</code></pre>
I prefer the former (note: that's a subjective statement). IMO there's nothing fundamentally more Golangish about the latter (if anything the fact that func's that begin with Test are special is kinda weird), and since Gomega's matchers are fluent in Go they know about things like zero values and errors having occured. Moreover, both Ginkgo and Gomega have been built to make testing asynchronous code (read: concurrent goroutines) easy and expressive. This isn't a carbon copy of RSpec/Cedar/Jasmine, it's a synthesis of the best ideas from those testing frameworks expressed in ways that cater specifically to Golang.<p>- Concerns about using interface{} and reflection seem odd to me. First off, the Go authors provide both of these things to precisely solve the sort of problem that Gomega is trying to solve. Nobody wants to write and maintain matchers that look like:<p><pre><code> Expect(foo).To(EqualInt64(3))
Expect(bar).To(EqualString("blarp"))
Expect(baz).To(EqualMyCustomAwesomeType(awesome))
</code></pre>
besides the reflect package's `DeepEqual` does a <i>great</i> job comparing `interface{}` to `interface{}` correctly.<p>Most importantly of all: we're all using interface{} <i>all</i> the time: `fmt.Sprintf("%d %f %s %v", ...)`!<p>And thanks for seeing the point @karma_fountain: Gomega's matchers have excellent reporting about what precisely went wrong when a matcher fails. Bare assertions lack this and a look through the Go tests shows a lot of reinventing-the-wheel to provide what probably amounts to inconsistent error output to the developer. Why not put that all in one place, call it a matcher library, and make it <i>dead easy</i> to write custom matchers?<p>- And @shoo: yes, thanks for pointing it out: the example is somewhat fabricated and isn't a compelling argument for BDD vs XUnit. It's hard to cook up a good BDD example in very short space!