Minimal and Beautiful Go testing framework

Overview

Goblin

Build Status Go Reportcard GoDoc License Release

A Mocha like BDD testing framework written in Go that requires no additional dependencies. Requires no extensive documentation nor complicated steps to get it running.

Why Goblin?

Inspired by the flexibility and simplicity of Node BDD and frustrated by the rigorousness of Go way of testing, we wanted to bring a new tool to write self-describing and comprehensive code.

What do I get with it?

  • Run tests as usual with go test
  • Colorful reports and beautiful syntax
  • Preserve the exact same syntax and behaviour as Node's Mocha
  • Nest as many Describe and It blocks as you want
  • Use Before, BeforeEach, After and AfterEach for setup and teardown your tests
  • No need to remember confusing parameters in Describe and It blocks
  • Use a declarative and expressive language to write your tests
  • Plug different assertion libraries
  • Gomega (supported so far)
  • Skip your tests the same way as you would do in Mocha
  • Automatic terminal support for colored outputs
  • Two line setup is all you need to get up running

How do I use it?

Since go test is not currently extensive, you will have to hook Goblin to it. You do that by adding a single test method in your test file. All your goblin tests will be implemented inside this function.

package foobar

import (
    "testing"
    . "github.com/franela/goblin"
)

func Test(t *testing.T) {
    g := Goblin(t)
    g.Describe("Numbers", func() {
        // Passing Test
        g.It("Should add two numbers ", func() {
            g.Assert(1+1).Equal(2)
        })
        // Failing Test
        g.It("Should match equal numbers", func() {
            g.Assert(2).Equal(4)
        })
        // Pending Test
        g.It("Should substract two numbers")
        // Excluded Test
        g.Xit("Should add two numbers ", func() {
            g.Assert(3+1).Equal(4)
        })
    })
}

Ouput will be something like:

Nice and easy, right?

Can I do asynchronous tests?

Yes! Goblin will help you to test asynchronous things, like goroutines, etc. You just need to add a done parameter to the handler function of your It. This handler function should be called when your test passes.

  ...
  g.Describe("Numbers", func() {
      g.It("Should add two numbers asynchronously", func(done Done) {
          go func() {
              g.Assert(1+1).Equal(2)
              done()
          }()
      })
  })
  ...

Goblin will wait for the done call, a Fail call or any false assertion.

How do I use it with Gomega?

Gomega is a nice assertion framework. But it doesn't provide a nice way to hook it to testing frameworks. It should just panic instead of requiring a fail function. There is an issue about that here. While this is being discussed and hopefully fixed, the way to use Gomega with Goblin is:

package foobar

import (
    "testing"
    goblin "github.com/franela/goblin"
    . "github.com/onsi/gomega"
)

func Test(t *testing.T) {
    g := goblin.Goblin(t)

    //special hook for gomega
    RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })

    g.Describe("lala", func() {
        g.It("lslslslsls", func() {
            Expect(1).To(Equal(10))
        })
    })
}

FAQ

How do I run specific tests?

If -goblin.run=$REGES is supplied to the go test command then only tests that match the supplied regex will run

Contributing

We do have a couple of issues pending. Feel free to contribute and send us PRs (with tests please 😄 ).

Special Thanks

Special thanks to Leandro Reox (Leitan) for the goblin logo.

Comments
  • fix regex flag parsing #74

    fix regex flag parsing #74

    Passed in flags like goblin.run are never parsed because the default testing package calls flag.Parse() before goblin calls flag.Parse(), which means the runRegex flag never gets set.

    Resolves #74

    Test manually:

    1. Make a new test file like flag_test.go
    package goblin
    
    import (
    	"testing"
    )
    
    func TestFlagRegex(t *testing.T) {
    	g := Goblin(t)
    
    	g.Describe("Test", func() {
    		g.It("Auth 1", func() {})
    		g.It("Auth 2", func() {})
    		g.It("Mismatched test", func() {})
    	})
    }
    
    
    1. run go test -timeout 30s -run ^TestFlagRegex -v -goblin.run=Auth
    2. the output will have Auth 1 and Auth 2, but not Mismatched test

    Some exploration of the bug:

    // Add this into the end of the Goblin() function 
    fmt.Println("......", os.Args[1:], timeout, *regexParam, "[", runRegex, "]", *regexParam != "")
    

    run go test -run ^TestHandleItRegexExec -goblin.run="TestsrunPass"

    ...... [-test.timeout=10m0s -test.run=^TestHandleItRegexExec -goblin.run=TestsrunPass] 5s TestsrunPass [ <nil> ] true
    
      TestItRegexExec Helper
        ✓ TestsrunFail
        ✓ TestsrunPass
        ✓ TestsrunPass
    
    
     3 tests complete (0 ms)
    --- FAIL: TestHandleItRegexExec (0.00s)
        goblin_test.go:480: Failed
    FAIL
    exit status 1
    FAIL	_/Users/sockol/Desktop/Projects/goblin	0.293s
    

    So this test doesnt parse the "runRegex" since flag.Parse() has been called

    if !flag.Parsed() {
    	parseFlags() // never runs, never sets "runRegex"
    }
    

    If we adjust the condition to be

    func Goblin(t *testing.T, arguments ...string) *G {
    	parseFlags()
    	...
    
    func parseFlags() {
    	//Flag parsing
    	if !flag.Parsed() {
    		flag.Parse()
    	}
    	if *regexParam != "" {
    		runRegex = regexp.MustCompile(*regexParam)
    	} else {
    		runRegex = nil
    	}
    }
    

    The command works as expected

     ~/De/P/goblin  on master *10 !2  go test -run ^TestHandleItRegexExec -goblin.run="TestsrunPass"
    ...... [-test.timeout=10m0s -test.run=^TestHandleItRegexExec -goblin.run=TestsrunPass] 5s TestsrunPass [ TestsrunPass ] true
    
      TestItRegexExec Helper
        ✓ TestsrunPass
        ✓ TestsrunPass
    
    
     2 tests complete (0 ms)
    PASS
    ok  	_/Users/sockol/Desktop/Projects/goblin	0.135s
    

    But the tests break - the new args passed into the "TestRegex" test are not parsed, [ runRegex] is not set

    ......  [-test.timeout=10m0s -goblin.run=matches] 5s  [ <nil> ] false
    
      Test
        1) Doesn't match regex
        ✓ It matches regex
        ✓ It also matches
    
    
     2 tests complete (0 ms)
     1 tests failed:
    
      1) Test Doesn't match regex:
    
        Regex shouldn't match
        	/Users/sockol/Desktop/Projects/goblin/goblin_test.go:312 +0x42
        	/Users/sockol/Desktop/Projects/goblin/goblin.go:231 +0x27
        	/Users/sockol/Desktop/Projects/goblin/goblin.go:231 +0x3e7
    --- FAIL: TestRegex (0.00s)
    	goblin_test.go:320: Failed
    
    opened by sockol 10
  • Random panic on runtime.errorString conversion

    Random panic on runtime.errorString conversion

    From time to time go test -v command fails with

    panic: runtime error: invalid memory address or nil pointer dereference [recovered]
        panic: interface conversion: interface is runtime.errorString, not string [recovered]
        panic: interface conversion: interface is runtime.errorString, not string
    [signal 0xb code=0x1 addr=0x0 pc=0x3b924]
    
    goroutine 4 [running]:
    testing.func·004()
        /usr/local/Cellar/go/1.1/src/pkg/testing/testing.go:348 +0xcd
    github.com/franela/goblin.func·001()
        ~/src/github.com/franela/goblin/goblin.go:156 +0x9d
    

    Unfortunately, I can't find appropriate scenario to reproduce this situation, but it happens quite often.

    opened by kachayev 8
  • Fixed a few race conditions

    Fixed a few race conditions

    List of changes

    • Structures
      • Added field It.failureMu of type sync.RWMutex
      • Added field DetailedReporter.executionTimeMu of type sync.RWMutex
      • Added field FakeReporter.executionTimeMu of type sync.RWMutex
    • Made the methods accessing the fields protected by the new mutexes Lock/RLock the mutex before accessing it

    Why?

    go test -race on this package revealed multiple race conditions, which should be fixed by this PR.

    Now, the default tests of this package pass with the -race flag without issues.

    opened by Neirpyc 7
  • Added interface to allow different printing styles.

    Added interface to allow different printing styles.

    This change is a no-op for existing goblin users. This is only useful if you are running in a terminal that doesn't understand the ansi color codes. This matters to users of go sublime because sublime isnt a terminal so the colors and check make the output hard to read.

    opened by iansmith 6
  • Feature Request: Xit() to Exclude Test

    Feature Request: Xit() to Exclude Test

    I saw issue #56 has been around for a while with the comment of not having time to add it, and noticed #60 came up recently. Thought I would take a stab at adding it.

    • Adds Itable interface for variations of It
    • Adds Xit struct and methods
    • Adds Yellow fancier for excluded outputs
    • Adds excluded output to reports
    • Updates README.md to include new functionality
    opened by dan9186 5
  • failing test suite

    failing test suite

    I'm running go test in this repo and the test suite reports a bunch of failures but I'm not sure if they are related to actual bugs or part of the testing. I'd like to add a new simple feature but the fact that I'm not sure if the test suite is passing or failing is a bit worrying.

    opened by mattetti 5
  • Fix assertion IsNil() failing when passing a nil slice

    Fix assertion IsNil() failing when passing a nil slice

    Previously, such code would fail:

    package main
    
    import (
    	. "github.com/franela/goblin"
    	"testing"
    )
    
    func Test(t *testing.T){
    	g := Goblin(t)
    	g.Describe("Assert(nilSlice).IsNil()", func(){
    		g.It("Should pass assertion", func(){
    			var slice []interface{} = nil
    			g.Assert(slice).IsNil() //fails
    		})
    	})
    }
    

    This is because a nil slice is not a nil pointer. Therefore, to know if an interface{} is a nil slice, we can check wether it is a slice or not with reflect.TypeOf(a.src).Kind() == reflect.Slice. In case it is a slice, we can use reflect.ValueOf(a.src).IsNil() to know if a slice is nil or not.

    This PR also adds two test functions TestIsNilWithSlice and TestIsNotNilWithSlice.

    opened by Neirpyc 4
  • Accept various types of messages in assertions

    Accept various types of messages in assertions

    Expand all assertions to accept various types of messages to emit as output when the expression evaluates to false. This changes permits unit tests to use any assertion call for returning a message instead of just IsTrue() and IsFalse().

    The change from accepting only strings to any value allows for simplification of unit tests that just print the error string.

    This allows replacing:

    if err != nil {
            g.Fail(err.Error())
    }
    

    With:

    g.Assert(err == nil).IsTrue(err)
    

    The logic to format the messages into output relies upon fmt.Sprintf(). It simply concatenates the messages together with one exception: messages that are only whitespace. In this case, it wraps the whitespace with square brackets to make it more obvious that a message was provided albeit unseen.

    Bump CI version of Go to 1.12 which is the oldest version still supported by the Go developers. It is also includes strings.Builder which is needed by the new assertion message code.

    Correct spelling and remove trailing spaces.

    opened by scfarley 4
  • Table driven tests will test only last item

    Table driven tests will test only last item

    Trying the below code. It should actually fail on first It as it has expected and actual values different.

    import (
    	"testing"
    
    	. "github.com/franela/goblin"
    )
    
    func Test(t *testing.T) {
    	g := Goblin(t)
    	// RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })
    	g.Describe("Holly tessst", func() {
    		loopableLoop := []struct {
    			expected string
    			actual   string
    		}{{
    			expected: "1",
    			actual:   "2",
    		},
    			{
    				expected: "2",
    				actual:   "2",
    			},
    		}
    
    		for _, te := range loopableLoop {
    			g.It(te.expected, func() {
    				g.Assert(te.expected).Equal(te.actual)
    			})
    		}
    	})
    }
    
    opened by viharm91 4
  • Regexp test selector does not seem to work.

    Regexp test selector does not seem to work.

    I cannot see the regexp flag -goblin.run working unless I comment out the flag.Parsed() check in the Goblin constructor. In my tests it seems to always be true even though I do not see where else the flag.Parse() is called.

    func Goblin(t *testing.T, arguments ...string) *G {
    	// if !flag.Parsed() {
    	parseFlags()
    	// }
    

    Removing the check seems to work well though.

    The command I run is as follows:

    $ go test ./pkg/... -v -goblin.run="regexp"
    

    OR

    $ go test ./pkg/... -v -args -goblin.run="regexp"
    

    EDIT: I am using go1.11

    opened by snobb 4
  • Add JustBeforeEach clause similar to ginkgo which adds more granularity

    Add JustBeforeEach clause similar to ginkgo which adds more granularity

    JustBeforeEach allows you to decouple creation from intialization. Initalization occurs in the JustBeforeEach using configuration specified and modified by a chain of BeforeEachs. This allows for a better code reuse in tests.

    JustBeforeEach fires after BeforeEach but before It for each It in the block. Similar to BeforeEach blocks JustBeforeEach from outer blocks has presedence over the local JustBeforeEach.

    For more info: https://onsi.github.io/ginkgo/#separating-creation-and-configuration-justbeforeeach

    The JustBeforeEach clause allows for doing this:

    var (
        param1, param2 int
        inst           Tested
    )
    
    g.Describe("Test Suite", func() {
        g.JustBeforeEach(func() {
            inst = NewTested(param1, param2)
        })
    
        g.Describe("Success", func() {
            g.BeforeEach(func() {
                param1 = 1
                param2 = 2
            })
    
            g.It("should succeed", func() {
                fmt.Println("inst initialized with new param1 and param2")
            })
        })
    
        g.Describe("Failure", func() {
            g.BeforeEach(func() {
                param1 = -1
                param2 = -2
            })
    
            g.It("should fail", func() {
                fmt.Println("inst initialized with new negative param1 and param2")
            })
        })
    })
    
    opened by snobb 4
  • Is it expected, that Goblin doesn't output anything if all tests pass?

    Is it expected, that Goblin doesn't output anything if all tests pass?

    I couldn't find anything about this in the README.md, but whenever I run my tests which all pass, Goblin actually won't output anything and I only see the standard go test output. Is this expected?

    opened by Dan6erbond 2
  • How to run each test in parallel in test suite?

    How to run each test in parallel in test suite?

    package foobar
    
    import (
        "testing"
        . "github.com/franela/goblin"
    )
    
    func Test(t *testing.T) {
        g := Goblin(t)
        g.Describe("Numbers", func() {
            // Passing Test
            g.It("Should add two numbers ", func() {
                g.Assert(1+1).Equal(2)
            })
            // Failing Test
            g.It("Should match equal numbers", func() {
                g.Assert(2).Equal(4)
            })
            // Pending Test
            g.It("Should substract two numbers")
            // Excluded Test
            g.Xit("Should add two numbers ", func() {
                g.Assert(3+1).Equal(4)
            })
        })
    }
    
    opened by HeykQA 5
  • NotEqual assertions

    NotEqual assertions

    Nice library, I'm loving the coloured output and the BDD style assertions.

    Just wondering if there is a NotEqual assertion equivalent available or planned?

    opened by andrewgarshyn 2
  • feat: add the ability to skip test suites, hooks

    feat: add the ability to skip test suites, hooks

    • Adds Skip, SkipIf, and Resume methods
    • Skips Before, After, et. al., hooks when there are no tests to actually run
    • Adds tests for skipping
    • Updates tests with nonsense math to pass linting
    • Updates to pass linting (Go standard)
    • Updates module to Go 1.16 (may not be desired upstream?)
    • Documents skipping functionality
    opened by shakefu 0
  • Request for describe comments to be matched with -goblin.run regexp

    Request for describe comments to be matched with -goblin.run regexp

    I'd like to run particular group of tests described via Describe(), just for developing purposes when I want to debug entire group, so i would really appreciate a separate flag, e.g -goblin.runFullName with the following behavior:

    diff --git a/goblin.go b/goblin.go
    index a4617db..078965c 100644
    --- a/goblin.go
    +++ b/goblin.go
    @@ -284,8 +284,30 @@ func (g *G) SetReporter(r Reporter) {
            g.reporter = r
     }
     
    +func (g *G) GetFullName(name string) string {
    +       parent := g.parent
    +       names := []string{name}
    +
    +       for parent != nil {
    +               names = append(names, parent.name)
    +               parent = parent.parent
    +       }
    +
    +       result := ""
    +       for _, n := range names {
    +               if len(result) == 0 {
    +                       result = n
    +                       continue
    +               }
    +
    +               result = n + "." + result
    +       }
    +
    +       return result
    +}
    +
     func (g *G) It(name string, h ...interface{}) {
    -       if matchesRegex(name) {
    +       if matchesRegex(g.GetFullName(name)) {
                    it := &It{name: name, parent: g.parent, reporter: g.reporter}
                    if g.parent == nil {
                            panic(fmt.Sprintf("It(\"%s\") block should be written inside Describe() block.", name))
    
    opened by alexey-komarov 4
Releases(0.0.2)
Owner
null
A yaml data-driven testing format together with golang testing library

Specimen Yaml-based data-driven testing Specimen is a yaml data format for data-driven testing. This enforces separation between feature being tested

Design it, Run it 1 Nov 24, 2022
Testing framework for Go. Allows writing self-documenting tests/specifications, and executes them concurrently and safely isolated. [UNMAINTAINED]

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

Esko Luontola 114 Sep 27, 2022
An always-on framework that performs end-to-end functional network testing for reachability, latency, and packet loss

Arachne Arachne is a packet loss detection system and an underperforming path detection system. It provides fast and easy active end-to-end functional

Uber Open Source 370 Nov 13, 2022
Full-featured test framework for Go! Assertions, mocking, input testing, output capturing, and much more! 🍕

testza ?? Testza is like pizza for Go - you could life without it, but why should you? Get The Module | Documentation | Contributing | Code of Conduct

Marvin Wendt 408 Nov 15, 2022
Golang HTTP client testing framework

flute Golang HTTP client testing framework Presentation https://speakerdeck.com/szksh/flute-golang-http-client-testing-framework Overview flute is the

Shunsuke Suzuki 17 Sep 27, 2022
API testing framework inspired by frisby-js

frisby REST API testing framework inspired by frisby-js, written in Go Proposals I'm starting to work on frisby again with the following ideas: Read s

_Hofstadter 274 Sep 27, 2022
🚀🌏 Orbital is a simple end-to-end testing framework for Go

Orbital is a test framework which enables a developer to write end to end tests just like one would writing unit tests. We do this by effectively copying the testing.T API and registering tests to be run periodically on a configured schedule.

Segment 79 Nov 18, 2022
BDD Testing Framework for Go

Jump to the docs | 中文文档 to learn more. To start rolling your Ginkgo tests now keep reading! If you have a question, comment, bug report, feature reque

Onsi Fakhouri 6.6k Nov 21, 2022
Framework of performance testing

Framework of performance testing fperf is a powerful and flexible framework which allows you to develop your own benchmark tools so much easy. You cre

null 337 Nov 8, 2022
Professional lightweight testing mini-framework for Go.

is Professional lightweight testing mini-framework for Go. Easy to write and read Beautifully simple API with everything you need: is.Equal, is.True,

Mat Ryer 1.5k Nov 26, 2022
espresso - a framework for testing BigQuery queries

espresso - a framework for testing BigQuery queries Goals Componentization: compose complex queries from smaller, reusable components Test driven deve

Tufin 7 Nov 18, 2022
Testy is a Go test running framework designed for Gametime's API testing needs.

template_library import "github.com/gametimesf/template_library" Overview Index Overview Package template_library is a template repository for buildin

Gametime United, Inc. 4 Jun 21, 2022
Fortio load testing library, command line tool, advanced echo server and web UI in go (golang). Allows to specify a set query-per-second load and record latency histograms and other useful stats.

Fortio Fortio (Φορτίο) started as, and is, Istio's load testing tool and now graduated to be its own project. Fortio is also used by, among others, Me

Fortio (Φορτίο) 2.8k Nov 28, 2022
Extremely flexible golang deep comparison, extends the go testing package and tests HTTP APIs

go-testdeep Extremely flexible golang deep comparison, extends the go testing package. Latest news Synopsis Description Installation Functions Availab

Maxime Soulé 329 Nov 26, 2022
A collection of packages to augment the go testing package and support common patterns.

gotest.tools A collection of packages to augment testing and support common patterns. Usage With Go modules enabled (go1.11+) $ go get gotest.tools/v3

null 370 Nov 28, 2022
End-to-end HTTP and REST API testing for Go.

httpexpect Concise, declarative, and easy to use end-to-end HTTP and REST API testing for Go (golang). Basically, httpexpect is a set of chainable bui

Victor Gaydov 2k Nov 24, 2022
HTTP traffic mocking and testing made easy in Go ༼ʘ̚ل͜ʘ̚༽

gock Versatile HTTP mocking made easy in Go that works with any net/http based stdlib implementation. Heavily inspired by nock. There is also its Pyth

Tom 1.7k Nov 23, 2022
HTTP mock for Golang: record and replay HTTP/HTTPS interactions for offline testing

govcr A Word Of Warning I'm in the process of partly rewriting govcr to offer better support for cassette mutations. This is necessary because when I

Seb C 137 Nov 18, 2022
A next-generation testing tool. Orion provides a powerful DSL to write and automate your acceptance tests

Orion is born to change the way we implement our acceptance tests. It takes advantage of HCL from Hashicorp t o provide a simple DSL to write the acceptance tests.

Wesovi Labs 45 Aug 31, 2022