Fix Home Needs

  • Subscribe to our RSS feed.
  • Twitter
  • StumbleUpon
  • Reddit
  • Facebook
  • Digg

Monday, 30 September 2013

Behavior-driven testing in Go with GoConvey (BDD in "golang")

Posted on 21:51 by Unknown

First: the built-in Go testing tools

Few things bring sweeter peace to the soul than making changes to Go code, then:

$ go test
...
PASS
ok

Go's built-in testing tools are good, but their structure doesn't easily allow for us to convey behavior. When we make an assertion, we assert that the opposite is not true instead of asserting that what we want is true:

if (a != b) {
    t.Errorf("Expected '%d' but got '%d'", a, b)
}

This has been very nice, but as projects get bigger, tests get more numerous, and structuring them so they are readable, avoid repetition, and clearly test specific behavior rather than just results becomes difficult to do idiomatically. (Plus, Go's default test output is hard to read.)

Enter GoConvey.

GoConvey is a library for behavior-driven development. It implements the same go test interface you're used to, and plays nicely in both default and verbose (go test -v) modes. GoConvey structures your tests in a way that makes them more readable and reliable. GoConvey has easy-to-read output that even uses colors (and if you're on Mac, Unicode easter eggs) for fast comprehension.

Finally: Your first GoConvey tests

Simply install GoConvey with:

$ go get github.com/smartystreets/goconvey

Then open your new test file. Be sure to name it something ending with "_test.go". It should look familiar to start (I'll be recreating this example file):

package examples

import (
. "github.com/smartystreets/goconvey/convey"
"testing"
)

func TestSpec(t *testing.T) {
}

Notice that we import the "convey" package from GoConvey with the dot notation. This is an acceptable practice for our purposes, as you will see, since this is all for testing your production code and none of it actually gets built into your executable.

To start testing, let's begin to fill out that TestSpec func:

func TestSpec(t *testing.T) {
Convey("Subject: Increment and decrement", t, nil)
}

This sets up our first test harness. We pass in a string which acts merely as a comment, then the testing.T object (but only our top-level Convey() call should have it! -- you'll see in a minute), then nil. For now, this means "nothing to see here, move along" -- and that test will be skipped. In order to be useful, we must replace nil with a func():

func TestSpec(t *testing.T) {
Convey("Subject: Increment and decrement", t, func() {
var x int

Convey("When incremented", func() {
x++
})
})
}

As you can see, any nested calls to Convey() shouldn't have "t" passed in.

Within your functions, you can set up your test at the appropriate scope. Above, we've defined a function to test the subject ("Increment and decrement") and given it an int to work with (x). You may want to avoid using := notation at higher scopes until you're done nesting Conveys. (Figuring out why is left as an exercise for the reader.)

Our second level of Convey, then, tests various paths or situations that the subject may encounter. The harness we've specified tests the paths when x is incremented. Now it's time to make assertions. We'll make two:

func TestSpec(t *testing.T) {
Convey("Subject: Integer incrementation and decrementation", t, func() {
var x int

Convey("Given a starting integer value", func() {
x = 42

Convey("When incremented", func() {
x++

Convey("The value should be greater by one", func() {
So(x, ShouldEqual, 43)
})
Convey("The value should NOT be what it used to be", func() {
So(x, ShouldNotEqual, 42)
})
})
})
})
}

The nested structure is incredibly helpful as projects grow.

Feel free to make several assertions in a row, within one convey, or in a loop. Check marks will be placed at the end of the verbose output to indicate that each one has passed (or an X if it didn't pass).

Oh -- did I mention that you can now run your tests by doing:

$ go test

I usually prefer verbose mode:

$ go test -v

And if you want your tests to run automatically when you save your test files:

$ python $GOPATH/src/github.com/smartystreets/goconvey/scripts/idle.py

Similarly, if you want verbose mode, tack a -v on to the end of that.

Available functions / assertions

This primer ends here, but that should get you started with BDD in Go. Be sure to check out the README for another once-over, and the Godoc documentation on the assertions and methods you can use, since I didn't cover most of them here. Also see the examples folder for even more that aren't yet documented, such as a Reset() function and similar things.

GoConvey is a new library but has lots of promise for writing more robust and test-documented code. As you encounter certain needs that aren't yet met by the library, open an issue or fork it and contribute.
Email ThisBlogThis!Share to XShare to Facebook
Posted in bdd, development, go, golang, testing, unit tests | No comments
Newer Post Older Post Home

0 comments:

Post a Comment

Subscribe to: Post Comments (Atom)

Popular Posts

  • Writing a Go ("golang") Web App with nginx, FastCGI, MySQL, JSON
    Want to write a web app in Go ("golang") like you write a PHP app? Go is cool since it's kind-of multi-threaded and has some ...
  • How to take FrontRunner from Provo to SLC airport
    I see this question a lot: how do I get from Provo or Orem to the SLC International Airport entirely by train (UTA FrontRunner/Trax)? Here I...
  • Behavior-driven testing in Go with GoConvey (BDD in "golang")
    First: the built-in Go testing tools Few things bring sweeter peace to the soul than making changes to Go code, then: $ go test ... PASS ok ...
  • Why yes, Go/Golang, I still want to read my CSV file!
    UPDATE: This appears to have been fixed and the fix  ships with   Go 1.2 . I like Go (1.1.1), but how disappointing that in order to read ...
  • Installing nginx / PHP / MySQL on Mac OS X Mountain Lion
    ** Update: See a quicker way to do this using Homebrew (this method uses Macports, and it's considerably more difficult). ** ... are yo...
  • Using Vagrant and cross-compiling Go (golang)
    This is mostly a memo-to-self about how to write Go code in my Mac environment, compile it there for a Linux environment, and run it in a pr...
  • Fix the Home and End keys on Mac OS X (Mountain Lion)
    If you use a keyboard that's not designed specifically for Macs, you probably are familiar with the annoying mapping of the Home and End...
  • Install nginx / PHP / MySQL on Mac OS X Mountain Lion with Homebrew
    Last time I wiped my Macbook Pro, I used Macports to install my web development environment . Doing it that way was really hard compared to ...
  • External hard drive backups while you sleep
    On most modern computers, there's an energy saver preference which will shut down your hard disks when the computer is idle or in "...

Categories

  • backup
  • bdd
  • byu
  • chrome
  • cli
  • command line
  • commute
  • compile
  • cross-compile
  • csv
  • development
  • dns
  • domain name
  • fastcgi
  • fcgi
  • go
  • golang
  • homebrew
  • inkscape
  • install
  • ip
  • ip address
  • ipaddress
  • itunes
  • javascript
  • keybinding
  • linux
  • mac
  • mountain lion
  • mysql
  • nginx
  • optimization
  • osx
  • parsing
  • pecl
  • php
  • printing
  • raspberry pi
  • security
  • ssd
  • terminal
  • testing
  • transportation
  • unit tests
  • vagrant

Blog Archive

  • ▼  2013 (16)
    • ►  November (1)
    • ►  October (1)
    • ▼  September (2)
      • Behavior-driven testing in Go with GoConvey (BDD i...
      • How to set up dynamic DNS in 5 minutes
    • ►  August (2)
    • ►  July (3)
    • ►  June (1)
    • ►  May (1)
    • ►  April (2)
    • ►  March (2)
    • ►  February (1)
  • ►  2012 (8)
    • ►  November (1)
    • ►  October (1)
    • ►  September (6)
Powered by Blogger.

About Me

Unknown
View my complete profile