biff

package module
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Jul 18, 2021 License: MIT Imports: 10 Imported by: 1

README

coverage badge GoDoc

Biff stands for BIFurcation Framework based on nesting cases or alternatives. You can take advantage of variable scoping to make your tests simpler and easier to read. Good choice for acceptance and use cases testing, it provides a BBD style exit.

Getting started

biff.Alternative("Instance service", func(a *biff.A) {

	s := NewMyService()

	a.Alternative("Register user", func(a *biff.A) {

		john := s.RegisterUser("john@email.com", "john-123")
		a.AssertNotNil(john)

		a.Alternative("Bad credentials", func(a *biff.A) {
			user := s.Login(john.Email, "bad-password")
			a.AssertNil(user)

		}).Alternative("Login", func(a *biff.A) {
			user := s.Login(john.Email, john.Password)
			a.AssertEqual(user, john)
		})

	})
})

Output:

=== RUN   TestExample
Case: Instance service
Case: Register user
    john is &example.User{Email:"john@email.com", Password:"john-123"}
Case: Bad credentials
    user is <nil>
-------------------------------
Case: Instance service
Case: Register user
    john is &example.User{Email:"john@email.com", Password:"john-123"}
Case: Login
    user is &example.User{Email:"john@email.com", Password:"john-123"}
-------------------------------
Case: Instance service
Case: Register user
    john is &example.User{Email:"john@email.com", Password:"john-123"}
-------------------------------
Case: Instance service
-------------------------------
--- PASS: TestExample (0.00s)
PASS

Get into the buggy line

In case of error, Biff will print something like this:

Case: Instance service
Case: Register user
    john is &example.User{Email:"john@email.com", Password:"john-123"}
Case: Login
    Expected: &example.User{Email:"maria@email.com", Password:"1234"}
    Obtained: &example.User{Email:"john@email.com", Password:"john-123"}
    at biff/example.TestExample.func1.1.2(0xc420096ac0
    /home/fulldump/workspace/my-project/src/example/users_test.go:84 +0x12

Navigating directly to the line where the fail was produced.

Isolated use cases

All possible bifurcations are tested in an isolated way.

BDD on the fly

You do not need to translate your tests behaviour to natural language. Biff will navigate through the execution stack and will parse portions of your testing code to pretty print your assertions.

This testing code:

a.AssertEqual(user, john)

will be printed as:

    user is &example.User{Email:"john@email.com", Password:"john-123"}

Take advantage of go function scope

Avoid testing helpers and auxiliar methods to maintain the status between tests, take advantage of language varialbe scope itself to write powerful tests easy to write and easy to read.

Supported assertions

Most commonly used assertions are implemented:

  • AssertEqual
  • AssertEqualJson
  • AssertNil
  • AssertNotNil
  • AssertNotEqual
  • AssertInArray
  • AssertTrue
  • AssertFalse

Contribute

Feel free to fork, make changes and pull-request to master branch.

If you prefer, create a new issue or email me for new features, issues or whatever.

Testing

Who will test the tester? ha ha

There are no tests for the moment but there will be, sooner than later.

Example project

This project includes an example project with some naive business logic plus some Biff tests.

Documentation

Overview

Package biff provides support for nested testing, useful for complex business logic, APIs, and stateful systems.

Typical usage:

biff.Alternative("Initial value", func(a *A) {
    value := 10
    a.AssertEqual(value, 10)

    a.Alternative("Plus 50", func(a *A) {
        // Here value == 10
        value += 50
        a.AssertEqual(value, 60)
    })

    a.Alternative("Multiply by 2", func(a *A) {
        // Here value == 10 again (it is an alternative from the parent)
        value *= 2
        a.AssertEqual(value, 20)
    })
})

Will produce this output:

Case: Initial value
    value is 10
Case: Plus 50
    value is 60
-------------------------------
Case: Initial value
    value is 10
Case: Multiply by 2
    value is 20
-------------------------------
Case: Initial value
    value is 10
-------------------------------

Other example:

func TestMyTest(t *testing.T) {
    Alternative("Login", func(a *A) {
        user := mySystem.Login("user@email.com", "123456")
        a.AssertEqual(user.Email, "user@email.com")
        a.Alternative("Do action 1", func(a *A) {
            // Do something
        })
        a.Alternative("Do action 2", func(a *A) {
            // Do something else
        })
        ...
    }
}

If some assertion fails, it will print expected value and `file:line` to get direct to the line, like this:

Expected: []string{"test a", "test a22"}
Obtained: []string{"test a", "test a2"}
at myservice.Test_isolation.func1.2(0xc420094a80 /.../project/item_test.go:21 +0x18
Example (BasicUsage)
Alternative("Initial value", func(a *A) {
	value := 10
	a.AssertEqual(value, 10)

	a.Alternative("Plus 50", func(a *A) {
		// Here value == 10
		value += 50
		a.AssertEqual(value, 60)
	})

	a.Alternative("Multiply by 2", func(a *A) {
		// Here value == 10 again (it is an alternative from the parent)
		value *= 2
		a.AssertEqual(value, 20)
	})
})
Output:

Case: Initial value
    value is 10
Case: Plus 50
    value is 60
-------------------------------
Case: Initial value
    value is 10
Case: Multiply by 2
    value is 20
-------------------------------
Case: Initial value
    value is 10
-------------------------------

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Alternative

func Alternative(title string, f F)

Alternative is the root use case and the test runner. It will execute all test alternatives defined inside.

func AssertEqual added in v1.3.0

func AssertEqual(obtained, expected interface{}) bool

AssertEqual return true if `obtained` is equal to `expected` otherwise it will print trace and exit.

func AssertEqualJson added in v1.3.0

func AssertEqualJson(obtained, expected interface{}) bool

AssertEqualJson return true if `obtained` is equal to `expected`. Prior to comparison, both values are JSON Marshaled/Unmarshaled to avoid JSON type issues like int vs float etc. Otherwise it will print trace and exit.

func AssertFalse added in v1.3.0

func AssertFalse(obtained interface{}) bool

AssertFalse return true if `obtained` is false, otherwise it will print trace and exit.

func AssertInArray added in v1.3.0

func AssertInArray(array interface{}, item interface{}) bool

AssertInArray return true if `item` match at least with one element of the array. Otherwise it will print trace and exit.

func AssertNil added in v1.3.0

func AssertNil(obtained interface{}) bool

AssertNil return true if `obtained` is nil, otherwise it will print trace and exit.

func AssertNotEqual added in v1.3.0

func AssertNotEqual(obtained, expected interface{}) bool

AssertNotEqual return true if `obtained` is not equal to `expected` otherwise it will print trace and exit.

func AssertNotNil added in v1.3.0

func AssertNotNil(obtained interface{}) bool

AssertNotNil return true if `obtained` is NOT nil, otherwise it will print trace and exit.

func AssertTrue added in v1.3.0

func AssertTrue(obtained interface{}) bool

AssertTrue return true if `obtained` is true, otherwise it will print trace and exit.

Types

type A

type A struct {

	// Title is the human readable short description for a test case.
	Title string

	// Description is an optional human detailed description for a test case,
	// needs to be filled inside alternative function.
	Description string
	// contains filtered or unexported fields
}

An A is a type passed to alternative functions to manage recursion status and keep human information information related to the test: `title` and `description`.

func (*A) Alternative

func (a *A) Alternative(title string, f F) *A

Alternative describes a new alternative case inside current case. It will be executed in a isolated branch.

func (*A) AssertEqual

func (a *A) AssertEqual(obtained, expected interface{}) bool

deprecated AssertEqual return true if `obtained` is equal to `expected` otherwise it will print trace and exit.

Example
Alternative("AssertEqual", func(a *A) {

	user := map[string]interface{}{
		"name": "John",
	}
	creator := map[string]interface{}{
		"name": "John",
	}

	AssertEqual(user, creator)

})
Output:

Case: AssertEqual
    user is creator (map[string]interface {}{"name":"John"})
-------------------------------

func (*A) AssertEqualJson

func (a *A) AssertEqualJson(obtained, expected interface{}) bool

deprecated AssertEqualJson return true if `obtained` is equal to `expected`. Prior to comparison, both values are JSON Marshaled/Unmarshaled to avoid JSON type issues like int vs float etc. Otherwise it will print trace and exit.

Example
Alternative("Json equality", func(a *A) {

	i := map[string]interface{}{
		"number": int(33),
	}
	f := map[string]interface{}{
		"number": float64(33),
	}

	AssertEqualJson(i, f)

})
Output:

Case: Json equality
    i is same JSON as f (map[string]interface {}{"number":33})
-------------------------------

func (*A) AssertFalse

func (a *A) AssertFalse(obtained interface{}) bool

deprecated AssertFalse return true if `obtained` is false, otherwise it will print trace and exit.

Example
Alternative("AssertFalse", func(a *A) {

	AssertFalse(1 == 2)

})
Output:

Case: AssertFalse
    1 == 2 is false
-------------------------------

func (*A) AssertInArray

func (a *A) AssertInArray(array interface{}, item interface{}) bool

deprecated AssertInArray return true if `item` match at least with one element of the array. Otherwise it will print trace and exit.

Example
Alternative("AssertInArray", func(a *A) {

	data := []string{"a", "b", "c"}
	myLetter := "b"

	AssertInArray(data, myLetter)

})
Output:

Case: AssertInArray
    data[1] is myLetter ("b")
-------------------------------

func (*A) AssertNil

func (a *A) AssertNil(obtained interface{}) bool

deprecated AssertNil return true if `obtained` is nil, otherwise it will print trace and exit.

Example
Alternative("AssertNil", func(a *A) {

	x := 1
	y := 2

	AssertTrue(x+y == 3)

})
Output:

Case: AssertNil
    x+y == 3 is true
-------------------------------

func (*A) AssertNotEqual

func (a *A) AssertNotEqual(obtained, expected interface{}) bool

deprecated AssertNotEqual return true if `obtained` is not equal to `expected` otherwise it will print trace and exit.

Example
Alternative("AssertNotEqual", func(a *A) {

	x := 1
	y := 2

	AssertNotEqual(x, y)

})
Output:

Case: AssertNotEqual
    x is not equal y (2)
-------------------------------

func (*A) AssertNotNil

func (a *A) AssertNotNil(obtained interface{}) bool

deprecated AssertNotNil return true if `obtained` is NOT nil, otherwise it will print trace and exit.

Example
Alternative("AssertNotNil", func(a *A) {

	user := &struct {
		Name string
	}{
		Name: "John",
	}

	AssertNotNil(user)

})
Output:

Case: AssertNotNil
    user is not nil (&struct { Name string }{Name:"John"})
-------------------------------

func (*A) AssertTrue

func (a *A) AssertTrue(obtained interface{}) bool

deprecated AssertTrue return true if `obtained` is true, otherwise it will print trace and exit.

Example
Alternative("AssertTrue", func(a *A) {

	x := 1
	y := 2

	AssertTrue(x+y == 3)

})
Output:

Case: AssertTrue
    x+y == 3 is true
-------------------------------

type F

type F func(a *A)

F is a callback alternative function passed to an `Alternative` with testing code.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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