ensure

package module
v0.4.3 Latest Latest
Warning

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

Go to latest
Published: May 8, 2023 License: MIT Imports: 1 Imported by: 0

README

ensure

A balanced test framework for Go.

Documentation CI Go Report Card codecov

Go Version Support

Only the last two minor versions of Go are officially supported.

Install

Library
$ go get github.com/JosiahWitt/ensure
CLI
# Requires Go 1.16+
$ go install github.com/JosiahWitt/ensure/cmd/ensure@latest

About

Ensure supports Go 1.13+ error comparisons (using errors.Is), and provides easy to read diffs (using deep.Equal). Ensure also supports mocks using GoMock.

Ensure was partially inspired by the is testing mini-framework.

Overview

Creating a test instance starts by calling:

ensure := ensure.New(t)

Then, ensure can be used as a function to asset a value is correct, using the pattern ensure(<actual>).<Method>(<expected>). Methods can also be called on ensure, using the pattern ensure.<Method>().

Configuring the CLI

The ensure CLI is configured using a .ensure.yml file which is located in the root of your Go Module (next to the go.mod file). Source code for the ensure CLI is located in the cmd/ensure directory.

Here is an example .ensure.yml file:

mocks:
  # Used as the directory path relative to the root of the module
  # for any interfaces that are not within internal directories.
  # Optional, defaults to "internal/mocks".
  primaryDestination: internal/mocks

  # Used as the directory path relative to internal directories within the project.
  # Optional, defaults to "mocks".
  internalDestination: mocks

  # Tidy mocks after generation completes.
  # Automatically runs 'ensure mocks tidy' after 'ensure mocks generate' completes.
  # Tidy removes any files that would not be generated by the provided packages list.
  # Optional, defaults to true.
  tidyAfterGenerate: true

  # Packages with interfaces for which to generate mocks
  packages:
    - path: github.com/my/app/some/pkg
      interfaces: [Iface1, Iface2]

Examples

Basic Testing
func TestBasicExample(t *testing.T) {
  ensure := ensure.New(t)
  ...

  // Methods can be called on ensure, for example, Run:
  ensure.Run("my subtest", func(ensure ensuring.E) {
    ...

    // To ensure a value is correct, use ensure as a function:
    ensure("abc").Equals("abc")
    ensure(produceError()).IsError(expectedError)
    ensure(doNotProduceError()).IsNotError()
    ensure(true).IsTrue()
    ensure(false).IsFalse()
    ensure("").IsEmpty()

    // Failing a test directly:
    ensure.Failf("Something went wrong, and we stop the test immediately")
  })
}
Table Driven Testing
func TestTableDrivenExample(t *testing.T) {
  ensure := ensure.New(t)

  table := []struct {
    Name    string
    Input   string
    IsEmpty bool
  }{
    {
      Name:    "with non empty input",
      Input:   "my string",
      IsEmpty: false,
    },
    {
      Name:    "with empty input",
      Input:   "",
      IsEmpty: true,
    },
  }

  ensure.RunTableByIndex(table, func(ensure Ensure, i int) {
    entry := table[i]

    isEmpty := strs.IsEmpty(entry.Input)
    ensure(isEmpty).Equals(entry.IsEmpty)
  })
}
Table Driven Testing with Mocks

Mocks can be generated by running ensure mocks generate, which wraps GoMock. To install the ensure CLI, see the Install section.

// db/db.go
type DB interface {
  Put(id string, data interface{}) error
  ...
}

// user/user.go
type UserStorage struct {
  DB db.DB
  ...
}

type User struct {
  ID    string
  Name  string
  ...
}

func (s *UserStorage) Save(ctx context.Context, u *User) error { ... }

// user/user_test.go
func TestTableDrivenMocksExample(t *testing.T) {
  ensure := ensure.New(t)

  type Mocks struct {
    mocksets.DefaultMocks
    DB *mock_db.MockDB // Mock of the db.DB interface generated by `ensure mocks generate`
  }

  table := []struct {
    Name          string
    Input         *user.User
    ExpectedError error

    Mocks      *Mocks            // Mocks to automatically initialize
    SetupMocks func(*Mocks)      // Optional function to allow for mock setup
    Subject    *user.UserStorage // Optional subject containing interfaces with which to assign the mocks
  }{
    {
      Name:    "with valid user",
      Input:   &user.User{
        ID:   "my-id",
        Name: "Mary",
      },
      SetupMocks: func(m *Mocks) {
        m.DB.EXPECT().Put("my-id", &user.User{
          ID:   "my-id",
          Name: "Mary",
        })
      },
    },
    {
      Name:    "with missing ID",
      Input:   &user.User{
        ID:   "",
        Name: "Mary",
      },
      SetupMocks: func(m *Mocks) {
        m.DB.EXPECT().Put("", &user.User{
          ID:   "",
          Name: "Mary",
        }).Return(errors.New("missing ID"))
      },
      ExpectedError: user.ErrSavingUser,
    },
  }

  ensure.RunTableByIndex(table, func(ensure Ensure, i int) {
    entry := table[i]

    err := entry.Subject.Save(entry.Mocks.Context, entry.Input)
    ensure(err).IsError(entry.ExpectedError)
  })
}

// mocksets/mocksets.go
type DefaultMocks struct {
  // Tag suppresses warning when it isn't used in the Subject
  Context *mockctx.MockContext `ensure:"ignoreunused"`
}

// mockctx/mockctx.go
type MockContext struct { context.Context }

// NEW method allows creating a MockContext, and is automatically called by ensure.
func (*MockContext) NEW() *MockContext {
  return &MockContext{Context: context.Background()}
}

Documentation

Overview

Package ensure is a balanced testing framework for Go 1.14+. It supports modern Go 1.13+ error comparisons (via errors.Is), and provides easy to read diffs (via deep.Equal).

Most of the implementation is in the ensuring package. ensure.New should be used to create an instance of the ensure framework, which allows shadowing the "ensure" package (like with the t variable in tests). This provides easy test refactoring, while still being able to access the underlying types via the ensuring package.

For example:

func TestBasicExample(t *testing.T) {
 ensure := ensure.New(t)
 ...

 // Methods can be called on ensure, for example, Run:
 ensure.Run("my subtest", func(ensure ensuring.Ensure) {
   ...

 	 // To ensure a value is correct, use ensure as a function:
 	 ensure("abc").Equals("abc")
 	 ensure(produceError()).IsError(expectedError)
 	 ensure(doNotProduceError()).IsNotError()
 	 ensure(true).IsTrue()
 	 ensure(false).IsFalse()
 	 ensure("").IsEmpty()

   // Failing a test directly:
   ensure.Failf("Something went wrong, and we stop the test immediately")
 })
}

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func New

func New(t ensuring.T) ensuring.E

New creates an instance of the ensure test framework using the current testing context.

Types

This section is empty.

Directories

Path Synopsis
cmd
ensure Module
Package ensurepkg contains the implementation for the ensure test framework.
Package ensurepkg contains the implementation for the ensure test framework.
Package ensuring contains the implementation for the ensure test framework.
Package ensuring contains the implementation for the ensure test framework.
internal/testhelper
Package testhelper implements helpers for testing ensure.
Package testhelper implements helpers for testing ensure.
exp
entable Module
experiment
entable Module
internal
mocks/mock_testctx
Package mock_testctx is a generated GoMock package.
Package mock_testctx is a generated GoMock package.
plugins
Package plugins contains interfaces and helpers related to internal plugins for ensure.
Package plugins contains interfaces and helpers related to internal plugins for ensure.
plugins/all
Package all combines all the plugins in the correct order.
Package all combines all the plugins in the correct order.
plugins/internal/id
Package id provides constants used throughout the plugins.
Package id provides constants used throughout the plugins.
plugins/internal/iterate
Package iterate provides helpers for iterating over reflect types and values.
Package iterate provides helpers for iterating over reflect types and values.
plugins/internal/mocks
Package mocks provides an abstracted wrapper around mocks.
Package mocks provides an abstracted wrapper around mocks.
plugins/internal/testhelper
Package testhelper provides helpers for testing the plugins.
Package testhelper provides helpers for testing the plugins.
plugins/mocks
Package mocks provides a plugin that initializes Mocks in the test entry.
Package mocks provides a plugin that initializes Mocks in the test entry.
plugins/setupmocks
Package setupmocks provides a plugin that runs SetupMocks for the provided Mocks.
Package setupmocks provides a plugin that runs SetupMocks for the provided Mocks.
plugins/subject
Package subject provides a plugin that initializes and populates test entry Subject fields using the provided mocks.
Package subject provides a plugin that initializes and populates test entry Subject fields using the provided mocks.
reflectensure
Package reflectensure provides a helper for identifying ensure types via reflection.
Package reflectensure provides a helper for identifying ensure types via reflection.
stringerr
Package stringerr creates errors to be printed by tests.
Package stringerr creates errors to be printed by tests.
tablerunner
Package tablerunner is an internal package that runs table-driven tests.
Package tablerunner is an internal package that runs table-driven tests.
testctx
Package testctx provides a context containing scoped test helpers.
Package testctx provides a context containing scoped test helpers.

Jump to

Keyboard shortcuts

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