gospec

package module
v0.0.0-...-a5cc0e4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 10, 2013 License: Apache-2.0 Imports: 11 Imported by: 0

README

GoSpec

GoSpec is a BDD-style testing framework for the Go programming language. It allows writing self-documenting tests/specs, and executes them in parallel and safely isolated.

Source code is available at http://github.com/orfjackal/gospec

For discussion, use the golang-nuts mailing list, at least until GoSpec has so many users that it requires its own mailing list. You may also contact GoSpec's developer, Esko Luontola, by email.

Quick Start

First you must have Go installed on your machine, as instructed in Installing Go.

Install and Update

Download GoSpec using the go get tool:

go get "github.com/orfjackal/gospec/src/gospec"

See go help get for more instructions on using the tool.

See "Version History" for any additional upgrade notes.

Sample Project

Make a copy of the hello-world-template directory to get started. You can run its tests with the go test command. All test files must end with _test.go and all specs must be listed in all_specs_test.go.

Running Specs

You can use the go test command to run GoSpec's specs. The integration with gotest requires a couple of lines of boilerplate: you'll need to write a gotest test method, where you list all your specs and call GoSpec. See all_specs_test.go in the examples directory for an example. Also all your specs must be in files whose names end with _test.go.

See gotest's documentation for instructions on how to use gotest.

GoSpec adds one additional parameter to gotest. Use the -print-all parameter to print a list of all specs: go test -print-all Otherwise only the failing specs are printed. The list of all specs can be useful as documentation.

Writing Specs

The following imports are needed. The first imports the gospec.Context interface and the second is needed for using GoSpec's expectation matchers (Equals, IsTrue, IsNil, Not(), Contains etc.) without having to prefix them with the package name. (In a future GoSpec version the matchers will be moved to their own package.)

import "github.com/orfjackal/gospec/src/gospec"
import . "github.com/orfjackal/gospec/src/gospec"

The specs are written as functions which take gospec.Context as a parameter. You can call the methods of Context to declare expectations and nested specs.

For examples on how to write specs, see the files in the examples directory.

Version History

1.x.x (2012-xx-xx)

  • ...

1.3.9 (2012-03-28)

UPGRADE NOTES: Check your imports - when using the go tool they are different than when using the old hand-written Makefiles.

  • Build using the go tool instead of Makefiles
  • Upgraded to Go 1 (weekly.2012-02-07)

1.3.8 (2011-08-04)

  • Upgraded to Go release.r59 (weekly.2011-07-07)

1.3.7 (2011-07-02)

  • Upgraded to Go release.r58 (weekly.2011-06-23)

1.3.6 (2011-05-04)

  • Upgraded to Go release.r57.1 (weekly.2011-04-27)

1.3.5 (2011-01-21)

  • Upgraded to Go release.2011-01-20

1.3.4 (2010-10-15)

  • Upgraded to Go release.2010-10-13

1.3.3 (2010-10-11)

  • Fixed an occasional off-by-one in exception stack trace line numbers

1.3.2 (2010-10-01)

  • Upgraded to Go release.2010-09-29

1.3.1 (2010-09-11)

  • Issue 754 was fixed in Go release.2010-09-06, so line numbers in GoSpec's stack traces are now correct
  • Fixed an occasional off-by-one in exception stack trace line numbers
  • Upgraded to Go release.2010-09-06

1.3.0 (2010-09-06)

UPGRADE NOTES: If you have written custom matchers, their result parameters' types have changed. Also the error messages are expected to be in a slightly different format. See expectation_syntax_test.go or GoSpec's built-in matchers for examples.

  • New error message format
  • Workaround for a bug in gedit 2.28.0 which caused stack traces to be sometimes non-clickable
  • Improved the stack traces to hide GoSpec internals also for root specs
  • Upgraded to Go release.2010-08-25

1.2.0 (2010-04-29)

UPGRADE NOTES: In your spec suite, replace r.AddSpec("SomeSpec", SomeSpec) with r.AddSpec(SomeSpec).

  • Recover from panics in specs and report their stack traces
  • Retrieve the spec function names using reflection, to avoid some boilerplate in the spec suite
  • Changes to error messages: function names and full file paths are now shown in the stack traces
  • Improved documentation and provided a hello world project template
  • Removed the deprecated c.Then() syntax
  • Upgraded to Go release.2010-04-13

1.1.0 (2010-03-08)

UPGRADE NOTES: In all your specs, replace *gospec.Context with gospec.Context in the spec's parameters. Add import . "gospec" to the imports and change every assertion of the old c.Then(x).Should.Equal(y) syntax to use the new c.Expect(x, Equals, y) syntax.

  • New expectation syntax. The old c.Then() syntax is deprecated and will be removed later.
  • New matchers: IsSame, IsNil, IsTrue, IsFalse, ContainsAll, ContainsAny, ContainsExactly, ContainsInOrder, ContainsInPartialOrder
  • Added Fibonacci numbers example
  • Added instructions about the style of naming and organizing specs
  • Minor changes to the print format of error messages
  • Upgraded to Go release.2010-02-04

1.0.0 (2009-12-30)

  • Initial release

Project Goals

The following are a must, because they enable using specification-style the way I prefer:

  • Unlimited Nesting - The specs can be organized into a nested hierarchy. This makes it possible to apply One Assertion Per Test which isolates the reason for a failure, because the specs are very fine-grained. Many unit testing tools allow only 2 levels of nesting (e.g. JUnit) and a few only 1 level (e.g. gotest), but for specification-style at least 3 levels are needed (e.g. JDave), and once you have 3 levels you might as well implement unlimited levels with the same abstraction.

  • Isolated Execution - The specs must be isolated from the side-effects of their sibling specs. Each spec will see only the side-effects of its parent specs. In effect, the parent specs work similar to the "before" (and "after") test code in many test frameworks, and by default none of the specs can see its siblings (there will be a way to override the default). Without this isolation, it would be harder to write reliable side-effect free specs, which in turn would force the specs to be organized differently than what was desired.

  • No Forced Words - Getting the words right was the starting point for BDD, so it is absurd that almost all of the BDD frameworks force the programmer to use fixed words (describe, it, should, given, when, then etc.) which incline the programmer to write spec names as sentences which begin or end with those words. You should be able to choose yourself the best possible words that fit a situation. GoSpec uses the syntax c.Specify("name", ...) for all levels in the specs, which leads to the word Specify becoming background noise, so that you ignore it and it does not force you to start your sentences with any particular word (using a meaningless word such as "Spec" would also be a good choice, as long as it is easy to pronounce when communicating with others).

The following are nice-to-haves, which make it more pleasant to use the framework:

  • Plain Text Names - You can use any Unicode characters in the spec names, because they are declared as strings. Using only those characters that are allowed in method names would be too limiting and hard to read.

  • Fluent API - The syntax for writing specs should be easily readable. It should be obvious that what an assert does, and which is the expected and which the actual value. Also writing the specs should be easy, requiring as little syntax as possible, but readability has always higher priority than writability.

  • Parallel Execution - Running the specs quickly (i.e. less than 10-20 seconds) is a must for using TDD, so being able to take advantage of all processing power is important, and multiple CPU cores is the only way to go fast in the foreseen future. GoSpec executes the specs using as much parallelism as possible (one goroutine for each leaf spec), so that it would be possible to utilize all available CPU cores (just remember to set GOMAXPROCS).

License

Copyright © 2009-2012 Esko Luontola <http://www.orfjackal.net>
This software is released under the Apache License 2.0.
The license text is at http://www.apache.org/licenses/LICENSE-2.0

Documentation

Index

Constants

View Source
const (
	ALL printMode = iota
	ONLY_FAILING
)

Variables

This section is empty.

Functions

func Contains

func Contains(actual_ interface{}, expected interface{}) (match bool, pos Message, neg Message, err error)

The actual collection must contain the expected value.

func ContainsAll

func ContainsAll(actual_ interface{}, expected_ interface{}) (match bool, pos Message, neg Message, err error)

The actual collection must contain all expected elements, but it may contain also other non-expected elements. The order of elements is not significant.

func ContainsAny

func ContainsAny(actual_ interface{}, expected_ interface{}) (match bool, pos Message, neg Message, err error)

The actual collection must contain at least one of the expected elements.

func ContainsExactly

func ContainsExactly(actual_ interface{}, expected_ interface{}) (match bool, pos Message, neg Message, err error)

The actual collection must contain all expected elements and nothing else. The order of elements is not significant.

func ContainsInOrder

func ContainsInOrder(actual_ interface{}, expected_ interface{}) (match bool, pos Message, neg Message, err error)

The actual collection must contain all expected elements, in the same order, and nothing else.

func ContainsInPartialOrder

func ContainsInPartialOrder(actual_ interface{}, expected_ interface{}) (match bool, pos Message, neg Message, err error)

The actual collection must contain all expected objects, in the same order, but it may contain also other non-expected objects. For example [1, 2, 2, 3, 4] contains in partial order [1, 2, 3]. See http://en.wikipedia.org/wiki/Partial_order for further information.

func Equals

func Equals(actual interface{}, expected interface{}) (match bool, pos Message, neg Message, err error)

The actual value must equal the expected value. For primitives the equality operator is used. All other objects must implement the Equality interface.

func Errorf

func Errorf(format string, args ...interface{}) error

Constructs an error message the same way as fmt.Sprintf(), but the string is created lazily when it is used, if it is used at all. This avoids unnecessary string parsing in matchers, because most of the time there are no failures and thus the error messages are not used.

func IsFalse

func IsFalse(actual interface{}, _ interface{}) (match bool, pos Message, neg Message, err error)

The actual value must be <false>.

func IsNil

func IsNil(actual interface{}, _ interface{}) (match bool, pos Message, neg Message, err error)

The actual value must be <nil>, or a typed nil pointer inside an interface value. See http://groups.google.com/group/golang-nuts/browse_thread/thread/d900674d491ef8d for discussion on how in Go typed nil values can turn into non-nil interface values.

func IsSame

func IsSame(actual interface{}, expected interface{}) (match bool, pos Message, neg Message, err error)

The actual value must be a pointer to the same object as the expected value.

func IsTrue

func IsTrue(actual interface{}, _ interface{}) (match bool, pos Message, neg Message, err error)

The actual value must be <true>.

func Main

func Main(runner *Runner)

Executes the specs which have been added to the Runner and prints the results to stdout. Exits the process after it is finished - with zero or non-zero exit value, depending on whether any specs failed.

func MainGoTest

func MainGoTest(runner *Runner, t *testing.T)

Executes the specs which have been added to the Runner and prints the results to stdout. Fails the surrounding test if any of the specs fails.

func Satisfies

func Satisfies(actual interface{}, criteria interface{}) (match bool, pos Message, neg Message, err error)

The actual value must satisfy the given criteria.

func Values

func Values(values ...interface{}) []interface{}

Easy array creation, to give multiple expected values to a matcher.

Types

type Context

type Context interface {

	// Creates a child spec for the currently executing spec. Specs can be
	// nested unlimitedly. The name should describe what is the behaviour being
	// specified by this spec, and the closure should express the same
	// specification as code.
	Specify(name string, closure func())

	// Makes an expectation. For example:
	//    c.Expect(theAnswer, Equals, 42)
	//    c.Expect(theAnswer, Not(Equals), 666)
	//    c.Expect(thereIsASpoon, IsFalse)
	Expect(actual interface{}, matcher Matcher, expected ...interface{})

	// Makes an assumption. Otherwise the same as an expectation,
	// but on failure will not continue executing the child specs.
	Assume(actual interface{}, matcher Matcher, expected ...interface{})
}

Context controls the execution of the current spec. Child specs can be created with the Specify method.

type Equality

type Equality interface {
	Equals(other interface{}) bool
}

type Error

type Error struct {
	Type       ErrorType
	Message    string
	Actual     string
	StackTrace []*Location
}

func (*Error) String

func (this *Error) String() string

type ErrorType

type ErrorType int
const (
	ExpectFailed ErrorType = iota
	AssumeFailed
	OtherError
)

type Location

type Location struct {
	// contains filtered or unexported fields
}

func (*Location) File

func (this *Location) File() string

func (*Location) FileName

func (this *Location) FileName() string

func (*Location) Line

func (this *Location) Line() int

func (*Location) Name

func (this *Location) Name() string

func (*Location) String

func (this *Location) String() string

type Matcher

type Matcher func(actual interface{}, expected interface{}) (match bool, pos Message, neg Message, err error)

Matchers are used in expectations to compare the actual and expected values.

Return values:

match: Should be true when `actual` and `expected` match, otherwise false.
pos:   Message for a failed expectation.
neg:   Message for a failed expectation when the matcher is combined with Not.
err:   Message for an unrecoverable error, for example if the arguments had a wrong type.

func IsWithin

func IsWithin(delta float64) Matcher

The actual value must be within delta from the expected value.

func Not

func Not(matcher Matcher) Matcher

Negates the meaning of a Matcher. Matches when the original matcher does not match, and the other way around.

func (Matcher) Match

func (matcher Matcher) Match(actual interface{}, optionalExpected ...interface{}) (match bool, pos Message, neg Message, err error)

Calls the matcher with the actual value and an optional expected value. If no expected value is given, then <nil> will be used.

type Message

type Message interface {
	Actual() interface{}
	Expectation() string
}

func Messagef

func Messagef(actual interface{}, expectationFormat string, expectationArgs ...interface{}) Message

type PrintFormat

type PrintFormat interface {
	PrintPassing(nestingLevel int, name string)
	PrintFailing(nestingLevel int, name string, errors []*Error)
	PrintSummary(passCount int, failCount int)
}

func DefaultPrintFormat

func DefaultPrintFormat(out io.Writer) PrintFormat

PrintFormat for production use.

func SimplePrintFormat

func SimplePrintFormat(out io.Writer) PrintFormat

PrintFormat for use in only tests. Does not print line numbers, colors or other fancy stuff. Makes comparing as a string easier.

type Printer

type Printer struct {
	// contains filtered or unexported fields
}

Printer formats the spec results into a human-readable format.

func NewPrinter

func NewPrinter(format PrintFormat) *Printer

func (*Printer) HideSummary

func (this *Printer) HideSummary()

func (*Printer) ShowAll

func (this *Printer) ShowAll()

func (*Printer) ShowOnlyFailing

func (this *Printer) ShowOnlyFailing()

func (*Printer) ShowSummary

func (this *Printer) ShowSummary()

func (*Printer) VisitEnd

func (this *Printer) VisitEnd(passCount int, failCount int)

func (*Printer) VisitSpec

func (this *Printer) VisitSpec(nestingLevel int, name string, errors []*Error)

type ResultCollector

type ResultCollector struct {
	// contains filtered or unexported fields
}

Collects test results for all specs in a reporting friendly format.

func (*ResultCollector) FailCount

func (r *ResultCollector) FailCount() int

func (*ResultCollector) PassCount

func (r *ResultCollector) PassCount() int

func (*ResultCollector) TotalCount

func (r *ResultCollector) TotalCount() int

func (*ResultCollector) Update

func (r *ResultCollector) Update(spec *specRun)

func (*ResultCollector) Visit

func (r *ResultCollector) Visit(visitor ResultVisitor)

type ResultVisitor

type ResultVisitor interface {
	VisitSpec(nestingLevel int, name string, errors []*Error)
	VisitEnd(passCount int, failCount int)
}

type Runner

type Runner struct {
	Parallel   bool
	BeforeEach func()
	AfterEach  func()
	// contains filtered or unexported fields
}

Runner executes the specs and collects their results.

func NewRunner

func NewRunner() *Runner

func (*Runner) AddNamedSpec

func (r *Runner) AddNamedSpec(name string, closure func(Context))

Adds a spec for later execution. Uses the provided name instead of retrieving the name of the spec function with reflection.

func (*Runner) AddSpec

func (r *Runner) AddSpec(closure func(Context))

Adds a spec for later execution. Example:

r.AddSpec(SomeSpec);

func (*Runner) Results

func (r *Runner) Results() *ResultCollector

func (*Runner) Run

func (r *Runner) Run()

Executes all the specs which have been added with AddSpec. The specs are executed using as many goroutines as possible, so that even individual spec methods are executed in multiple goroutines.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL