Download - TDD in Go with Ginkgo and Gomega
![Page 2: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/2.jpg)
About Me
Eddy Reyes. Cofounder of Tasqr
(www.tasqr.io)
● Automates application deployment /
configuration without code or config files.
Previously hacked lots of code at:
● IBM, Lifesize, Click Security
![Page 3: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/3.jpg)
Overview of Presentation
● Explain what TDD iso Not necessarily proselytizing that you must do it.
o I dislike many TDD-related presentations, they don’t
match my experience, they don’t stress what’s
important IMO.
● What Tools Does Go Have to Help You Do
TDD?o Ginkgo and Gomega, many others
![Page 4: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/4.jpg)
Further TDD Reading
Uncle Bob Martin● http://blog.8thlight.com/uncle-bob/archive.html
Kent Beck● Extreme Programming Explained (book)
Is TDD Dead? (video debates)● Kent Beck, Martin Fowler, DHH
● https://www.youtube.com/watch?v=z9quxZsLcfo (part 1)
![Page 5: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/5.jpg)
What Isn’t TDD?
● NOT just having written tests
● NOT a way to feel like you’re going fast
● NOT the Silver Bullet that saves software
engineering
● NOT like Axe, which makes you irresistible
to the opposite sex :-)
![Page 6: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/6.jpg)
What Is TDD?
● A process you follow when writing software.
● The process goes like this:o You write a test that defines an expected outcome in
your program.
o You watch the test fail.
o You change the program until your test passes.
● Adding tests to an already substantial
untested program isn’t necessarily TDD.
![Page 7: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/7.jpg)
How Do You Do TDD?
● In order to effectively follow the TDD pattern,
you must first understand your design.o Tests are rigid. Learning is free-form.
o You learn by hacking and breaking things.
o Tests ensure things don’t break.
● TDD helps you SHIP, not LEARN
![Page 8: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/8.jpg)
Learn vs. Ship
● Learning is free-form exploration.
Experiment, play, break things.o DO NOT SHIP THIS CODE!
o After you learn your design, step away from the
keyboard, and start anew.
● Shippingo Code ends up in a product used by customers.
o Quality is important!
![Page 9: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/9.jpg)
Tests Are Design!
● If tests are comprehensive, they are a formal
specification of your program.
● Writing a test is expressing the design of
your program’s functionality.
● To truly serve as a spec, tests must be:o Clean, readable
o Follow some consistent notation
![Page 10: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/10.jpg)
Test/Spec Notation
GIVEN
● Precondition 1...N
WHEN
● Call into your program
THEN
● Assert Condition 1...N
![Page 11: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/11.jpg)
A Test Framework Needs...
● Clean, simple notation
● Clean setup/teardown of dependencieso Idempotent, independent tests!
● Clean separation from tested code
● Simple runner mechanism
● Good reportingo test results
o coverage maps
![Page 12: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/12.jpg)
Testing in Go
● Test runnero go test
● Separates test code from producto *_test.go
● Comes with a test writing libraryo “testing” package
● Comes with coverage reporting toolso Beautiful HTML output
![Page 13: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/13.jpg)
“testing” Package
● Allows your to write test functions.
● Nice benchmarking utility
● Tests are basically blocks of code :(func TestXXX(t *testing.T) {
// setup stuff
// call your code
if something.State != WhatIWant {
t.Fail()
}
}
![Page 14: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/14.jpg)
Better Test-Writing Library
● go command has great tooling.
● Need a better notation for specifying tests.
…
Ginkgo and Gomega is a step forward!
… but not perfect!
![Page 15: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/15.jpg)
Ginkgo and Gomega
● Ginkgoo Compatible with “go test” but also comes with its
own test runner
o BDD-style test notation
o Expressive structuring of tests
● Gomegao “Matching” library
o Allows for expressive assert-like statements
![Page 16: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/16.jpg)
Ginkgo
● Tests expressed as English statementso In the BDD tradition of Cucumber, et. al.
var _ = Describe(“My component”, func() {
It(“Does something special”, func() {
MyFunction()
Expect(MyVar).To(Equal(10))
})
})
![Page 17: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/17.jpg)
Gomega
● Assertion languageExpect(number).To(Equal(10))
Expect(value).To(BeNumerically(“<”, 20))
Expect(someMap).To(Equal(otherMap)) // does reflect.DeepEqual()
Expect(someMap).To(BeEquivalent(otherMap)) // allows different types
Expect(myPtr).ToNot(BeNil())
Expect(flag).To(BeFalse())
Expect(err).ToNot(HaveOccurred())
Expect(err).To(MatchError(“my error message”))
![Page 18: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/18.jpg)
Ginkgo and Dependencies● setup/teardown:
var _ = Describe(“my config object”, func() {
var (
configObj *config.MyConfig
tempDir string
)
BeforeEach(func() {
var err error
tempDir, err = ioutil.TempDir(“”, “test-dir”)
Expect(err).ToNot(HaveOccurred())
configObj = config.NewConfig()
})
![Page 19: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/19.jpg)
Ginkgo and DependenciesIt(“Saves itself to file”, func() {
configObj.Save(tempDir)
restoredConfig := config.FromFile(configObj.Filename)
Expect(*restoredConfig).To(Equal(*configObj))
})
AfterEach(func() {
os.RemoveAll(tempDir)
})
}) // end Describe()
![Page 20: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/20.jpg)
Ginkgo and Dependencies
● Ginkgo heavily relies on closures and
closure variables to manage dependencies.o Resist the temptation to share state among tests!
● Nested dependencieso Within a Describe block, you can nest:
Context block
More It’s and Before/AfterEach’s
![Page 21: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/21.jpg)
Nested Dependenciesvar _ = Describe(“My component”)
var configObj config.MyConfig
BeforeEach(func() {
configObj = config.NewConfig()
})
It(“Does test1”, func() {
// configObj is setup
})
![Page 22: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/22.jpg)
Nested DependenciesContext(“With a fake HTTP server configured”, func() {
var testServer httptest.Server
BeforeEach(func() {
testServer = httptest.NewServer(<fake handler>)
})
It(“Does test2”, func() {
configObj.ServerUrl = testServer.URL
configObj.DoSomething() ...
})
})
![Page 23: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/23.jpg)
Testing Notation + Ginkgo
● Obviously, Ginkgo was not designed with my
exact notation in mind…
● However, it maps to it without too much
difficulty.
![Page 24: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/24.jpg)
Testing Notation + Ginkgovar _ = Describe(“my component”, func() {
// GIVEN
BeforeEach(func () {
})
It(“Does something useful”, func() {
// WHEN
CallSomething()
// THEN
Expect(stuff).To((Equal(something))
})
})
![Page 25: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/25.jpg)
Alternate Notation Stylevar _ = Describe(“my component”, func() {
BeforeEach(func() {...}) //
GIVEN
It(“Does something useful”, func() { // WHEN
closureVar = CallSomething()
})
AfterEach(func() {
Expect(closureVar).To(Equal(something)) // THEN
})
})
![Page 26: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/26.jpg)
Ginkgo Bootstrap
● Ginkgo integrates with go test
● You must use the ginkgo command to
generate boilerplate code:
$ cd mypackage/ # within $GOPATH/src
$ ginkgo bootstrap
…
$ ls
mypackage_suite_test.go
![Page 27: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/27.jpg)
Ginkgo Bootstrappackage mypackage_test // NOT THE SAME AS mypackage!!!
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing"
)
func TestConfig(t *testing.T) { // go test integration boilerplate!
RegisterFailHandler(Fail)
RunSpecs(t, "Mypackage Suite")
}
![Page 28: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/28.jpg)
Ginkgo Generate
● The generated suite calls the generated test
files:$ ginkgo generate
…
$ ls
mypackage_suite_test.go mypackage_test.go
…
$ cat mypackage_test.go
...
![Page 29: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/29.jpg)
Ginkgo Generatepackage mypackage_test // NOT THE SAME AS mypackage!!
import (
. “mypackage”
. “github.com/onsi/ginkgo”
. “github.com/onsi/gomega”
)
var _ = Describe(“Mypackage test”, func() {
})
![Page 30: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/30.jpg)
Assessing Ginkgo/Gomega
Test Notation
● The BDD-style english annotations help
readability a little bit...
● Closures are a slippery slope!o Too much code: declare closure vars, must also
initialize in BeforeEach to ensure test
idempotency!
![Page 31: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/31.jpg)
Assessing Ginkgo/Gomega
● Complex dependencies are doableo Accomplished by nesting Describe/Context/
BeforeEach’s
o However, your tests must be inserted in ever-more
nested closures
Can get kinda complicated!
● Gomega assertionso Flow nicely when read aloud
o Too complex as a formal notation
![Page 32: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/32.jpg)
Assessing Ginkgo/Gomega
● Overall test notation grade: C+/B-o Depends on my mood and how complicated my test
needs to get.
o Worst part about it is that your test file easily grows
way too long, and thus harder to comprehend as a
spec.
● Good enough to get our job done with high
quality at Tasqr.
![Page 33: TDD in Go with Ginkgo and Gomega](https://reader036.vdocuments.us/reader036/viewer/2022081404/559845b21a28ab0e078b45a5/html5/thumbnails/33.jpg)
Go TDD Roundup
Questions?