tag | 6afbad6e5aae5a17e6430f0ecd5fd8f096ccb097 | |
---|---|---|
tagger | Michael Whatcott <mdwhatcott@gmail.com> | Mon Oct 14 21:59:36 2013 |
object | 5833d05b744f9c32d40d37011a7afea972b1bc5e |
Web UI and server work together well, parsing of go test output is robust.
commit | 5833d05b744f9c32d40d37011a7afea972b1bc5e | [log] [tgz] |
---|---|---|
author | Michael Whatcott <mdwhatcott@gmail.com> | Mon Oct 14 21:54:50 2013 |
committer | Michael Whatcott <mdwhatcott@gmail.com> | Mon Oct 14 21:54:50 2013 |
tree | 73ac13869018193be6de2899809a14b28525f079 | |
parent | e80a408242c4c2021c4ce42dae88e617ee006d70 [diff] |
Cleanup (removed TODO items).
Welcome to GoConvey, a yummy BDD tool for gophers. Use it in the browser or in the terminal. Either way you choose, the output is a pleasure to read and work with.
Features:
go test
Jump to:
$ go get github.com/smartystreets/goconvey $ go install github.com/smartystreets/goconvey/web/server
Make a test, for example:
func TestSpec(t *testing.T) {
Convey("Given some integer with a starting value", t, func() {
x := 1
Convey("When the integer is incremented", func() {
x++
Convey("The value should be greater by one", func() {
So(x, ShouldEqual, 2)
})
})
})
}
Start up the GoConvey web server at your project's path:
$ $GOPATH/bin/server
Then open your browser to:
http://localhost:8080
There you have it. As long as GoConvey is running, test results will automatically update in your browser window. The design is responsive, so you can squish the browser real tight if you need to put it beside your code.
Want to use the terminal instead? Just do what you do best:
$ go test
Or if you want the output to include the story:
$ go test -v
If not all your tests are yet written in GoConvey, the web UI you opened in your browser also works for traditional Go tests! (But it's not quite as cool that way.)
go test -v
):Tests pass:
Test fail:
Test panic:
See the examples folder. We recommend reviewing isolated_execution_test.go for a more thorough understanding of how tests are composed, and how they actually work.
For an easier way: open your browser to the web UI and click “Code Gen” in the top-right. Then describe your program's behavior in a natural, flowing way, for example (make sure you convert indents to tabs, as GitHub transformed them to spaces):
TestSpec Subject: Integer incrementation and decrementation Given a starting integer value When incremented The value should be greater by one The value should NOT be what it used to be When decremented The value should be lesser by one The value should NOT be what it used to be
The skeleton of your test file will be stubbed out automatically as you type. There are a few things to notice about this:
_test.go
file.Public functions are documented using GoDoc conventions. See the [godoc.org page for this project] (http://godoc.org/github.com/smartystreets/goconvey) for the details.
Concise mode (default):
$ cd $GOPATH/src/github.com/smartystreets/goconvey/examples $ go test ..... 5 assertions and counting .... 9 assertions and counting PASS ok github.com/smartystreets/goconvey/examples 0.022s
Verbose mode:
$ cd $GOPATH/src/github.com/smartystreets/goconvey/examples $ go test -v === RUN TestScoring Subject: Bowling Game Scoring Given a fresh score card When all gutter balls are thrown The score should be zero ✔ When all throws knock down only one pin The score should be 20 ✔ When a spare is thrown The score should include a spare bonus. ✔ When a strike is thrown The score should include a strike bonus. ✔ When all strikes are thrown The score should be 300. ✔ 5 assertions and counting --- PASS: TestScoring (0.00 seconds) === RUN TestSpec Subject: Integer incrementation and decrementation Given a starting integer value When incremented The value should be greater by one ✔ The value should NOT be what it used to be ✔ When decremented The value should be lesser by one ✔ The value should NOT be what it used to be ✔ 9 assertions and counting --- PASS: TestSpec (0.00 seconds) PASS ok github.com/smartystreets/goconvey/examples 0.023s
Happy? Well, it gets even better with the auto-reload script. This script detects changes below the directory where it is run and recurses that location, running go test
wherever it finds *_test.go
files. This means that once it‘s running you don’t ever have to leave your editor to run tests. It also accepts the -v
argument for verbose mode. Check it out:
$ cd $GOPATH/src/github.com/smartystreets/goconvey/examples $ $GOPATH/src/github.com/smartystreets/goconvey/scripts/idle.py -------------------------------------- 1 -------------------------------------- ..... 5 assertions and counting .... 9 assertions and counting PASS ok github.com/smartystreets/goconvey/examples 0.022s (now waiting for you to save changes to the application under test...)
Here's the listing of assertions that this project aims to implement (see the examples folder for actual usage):
Assertions |
---|
General Equality |
So(thing, ShouldEqual, thing2) |
So(thing, ShouldNotEqual, thing2) |
So(thing, ShouldResemble, thing2) |
So(thing, ShouldNotResemble, thing2) |
So(thing, ShouldPointTo, thing2) |
So(thing, ShouldNotPointTo, thing2) |
So(thing, ShouldBeNil, thing2) |
So(thing, ShouldNotBeNil, thing2) |
So(thing, ShouldBeTrue) |
So(thing, ShouldBeFalse) |
Numeric Quantity comparison |
So(1, ShouldBeGreaterThan, 0) |
So(1, ShouldBeGreaterThanOrEqualTo, 0) |
So(1, ShouldBeLessThan, 2) |
So(1, ShouldBeLessThanOrEqualTo, 2) |
So(1.1, ShouldBeBetween, .8, 1.2) |
So(1.1, ShouldNotBeBetween, 2, 3) |
So(1.1, ShouldBeBetweenOrEqual, .9, 1.1) |
So(1.1, ShouldNotBeBetweenOrEqual, 1000, 2000) |
Collections |
So([]int{2, 4, 6}, ShouldContain, 4) |
So([]int{2, 4, 6}, ShouldNotContain, 5) |
So(4, ShouldBeIn, ...[]int{2, 4, 6}) |
So(4, ShouldNotBeIn, ...[]int{1, 3, 5}) |
Strings (and []byte?) |
So(“asdf”, ShouldStartWith, “as”) |
So(“asdf”, ShouldNotStartWith, “df”) |
So(“asdf”, ShouldEndWith, “df”) |
So(“asdf”, ShouldNotEndWith, “df”) |
So(“asdf”, ShouldContain, “sd”) // optional ‘expected occurences’ arguments? |
So(“asdf”, ShouldNotContain, “er”) |
So(“adsf”, ShouldBeBlank) |
So(“asdf”, ShouldNotBeBlank) |
panics |
So(func(), ShouldPanic) |
So(func(), ShouldNotPanic) |
So(func(), ShouldPanicWith, "") // or errors.New(“something”) |
So(func(), ShouldNotPanicWith, "") // or errors.New(“something”) |
Type checking |
So(1, ShouldHaveSameTypeAs, 0) |
So(1, ShouldNotHaveSameTypeAs, “asdf”) |
time |
So(time.Now(), ShouldHappenBefore, time.Now()) |
So(time.Now(), ShouldHappenOnOrBefore, time.Now()) |
So(time.Now(), ShouldHappenAfter, time.Now()) |
So(time.Now(), ShouldHappenOnOrAfter, time.Now()) |
So(time.Now(), ShouldHappenBetween, time.Now(), time.Now()) |
So(time.Now(), ShouldHappenOnOrBetween, time.Now(), time.Now()) |
So(time.Now(), ShouldNotHappenOnOrBetween, time.Now(), time.Now()) |
So(time.New(), ShouldHappenWithin, duration, time.Now()) |
So(time.New(), ShouldNotHappenWithin, duration, time.Now()) |
Thanks to github.com/jacobsa for his excellent oglematchers library, which is what many of these methods make use of to do their jobs.
Sometimes a test suite will might need an assertion that is too specific to be included in this tool. Not to worry, simply implement a function with the following signature (fill in the bracketed parts and string values):
func should<do-something>(actual interface, expected ...interface{}) string { if <some-important-condition-is-met(actual, expected)> { return "" // empty string means the assertion passed } else { return "some descriptive message detailing why the assertion failed..." } }
Suppose I implemented the following assertion:
func shouldScareGophersMoreThan(actual interface, expected ...interface{}) string {
if actual == "BOO!" && expected[0] == "boo" {
return ""
} else {
return "Ha! You'll have to get a lot friendlier with the capslock if you want to scare a gopher!"
}
}
I can then make use of the assertion function when calling the So(...)
method in the tests:
Convey("All caps always makes text more meaningful", func() {
So("BOO!", shouldScareGophersMoreThan, "boo")
})
Convey
Registrations:Changing a Convey
to SkipConvey
prevents the func()
associated with that call from running. This also has the consequence of preventing any nested Convey
registrations from running. The reporter will indicate that the registration was skipped.
SkipConvey("Important stuff", func() { // This func() will not be executed! Convey("More important stuff", func() { So("asdf", ShouldEqual, "asdf") }) })
Using SkipConvey
has nearly the same effect as commenting out the test entirely. However, this is preferred over commenting out tests to avoid the usual “declared/imported but not used” errors. Usage of SkipConvey
is intended for temporary code alterations.
Convey
Registrations:When composing Convey
registrations sometimes it's convenient to use nil
instead of an actual func()
. This allows you to do that and it also provides an indication in the report that the registration is not complete.
Convey("Some stuff", func() { // This will show up as 'skipped' in the report Convey("Should go boink", nil) }
So
Assertions:Similar to SkipConvey
, changing a So
to SkipSo
prevents the execution of that assertion. The report will show that the assertion was skipped.
Convey("1 Should Equal 2", func() { // This assertion will not be executed and will show up as 'skipped' in the report SkipSo(1, ShouldEqual, 2) })
And like SkipConvey
, this function is only intended for use during temporary code alterations.