package
0.0.4
Repository: https://github.com/go-dawn/pkg.git
Documentation: pkg.go.dev

# README

Deck

Make testing easier and under control and every package more reliable!

Usages

os.Exit

Use var osExit = deck.OsExit to replace os.Exit.

import (
	"github.com/go-dawn/pkg/deck"
	"github.com/stretchr/testify/assert"
)

var osExit = deck.OsExit

func TestSomeFunction(t *testing.T) {
	var count int32
	deck.SetupOsExit(func(code int) {
		atomic.AddInt32(&count, int32(code))
	})
	defer deck.TeardownOsExit()

	SomeFunction()

	assert.Equal(t, int32(100), atomic.LoadInt32(&count))
}

func SomeFunction() {
	osExit(100)
}

exec.Command

Use var execCommand = deck.ExecCommand to replace exec.Command. And the TestHelperCommand test function must be added in one of the test file in the package. You must use deck.HandleCommand function and determine the output of the executed command.

import (
	"github.com/go-dawn/pkg/deck"
	"github.com/stretchr/testify/assert"
)

var execCommand = deck.ExecCommand

func TestSomeFunction(t *testing.T) {
	at := assert.New(t)

	t.Run("success", func(t *testing.T) {
		deck.SetupCmd()
		defer deck.TeardownCmd()

		b, err := SomeFunction()
		at.Nil(err)
		at.Equal("[test function]", string(b))
	})

	t.Run("error", func(t *testing.T) {
		deck.SetupCmdError()
		defer deck.TeardownCmd()

		b, err := SomeFunction()
		at.NotNil(err)
		at.Equal("", string(b))
	})

	t.Run("stderr", func(t *testing.T) {
		deck.SetupCmdStderr()
		defer deck.TeardownCmd()

		b, err := SomeFunction()
		at.NotNil(err)
		at.Equal("[test function]", string(b))
	})
}

func TestHelperCommand(t *testing.T) {
	deck.HandleCommand(func(args []string, expectStderr bool) {
		if expectStderr {
			_, _ = fmt.Fprintf(os.Stderr, "%v", args)
			os.Exit(1)
		}
		_, _ = fmt.Fprintf(os.Stdout, "%v", args)
	})
}

func SomeFunction() ([]byte, error) {
	cmd := execCommand("test", "function")
	return cmd.CombinedOutput()
}

exec.LookPath

Use var execLookPath = deck.ExecLookPath to replace exec.LookPath.

import (
	"github.com/go-dawn/pkg/deck"
	"github.com/stretchr/testify/assert"
)

var execLookPath = deck.ExecLookPath

func TestSomeFunction(t *testing.T) {
	at := assert.New(t)

	t.Run("success", func(t *testing.T) {
		SetupExecLookPath()
		defer TeardownExecLookPath()

		bin, err := SomeFunction()

		at.Nil(err)
		at.Equal("test", bin)
	})

	t.Run("error", func(t *testing.T) {
		SetupExecLookPathError()
		defer TeardownExecLookPath()

		bin, err := SomeFunction()

		at.Equal(ErrLookPath, err)
		at.Equal("", bin)
	})
}

func SomeFunction() (string, error) {
	return execLookPath("test")
}

os.Stdout

Use var stdout = deck.Stdout to replace os.Stdout.

import (
	"github.com/go-dawn/pkg/deck"
	"github.com/stretchr/testify/assert"
)

var stdout = deck.Stdout

func TestSomeFunction(t *testing.T) {
	at := assert.New(t)

	deck.RedirectStdout()

	SomeFunction()

	output := deck.DumpStdout()

	at.Equal("stdout", output)
}

func SomeFunction() {
	_, _ = fmt.Fprint(stdout, "stdout")
}

os.Stderr

Use var stderr = deck.Stderr to replace os.Stderr.

import (
	"github.com/go-dawn/pkg/deck"
	"github.com/stretchr/testify/assert"
)

var stderr = deck.Stderr

func TestSomeFunction(t *testing.T) {
	at := assert.New(t)

	deck.RedirectStderr()

	SomeFunction()

	output := deck.DumpStderr()

	at.Equal("stderr", output)
}

func SomeFunction() {
	_, _ = fmt.Fprint(stderr, "stderr")
}

os.Environment

We can override or set environment and restore them back during testing.

import (
	"github.com/go-dawn/pkg/deck"
	"github.com/stretchr/testify/assert"
)

func TestSomeFunction(t *testing.T) {
	at := assert.New(t)

	key1 := "DAWN_DECK"
	key2 := "DAWN_DECK2"
	oldValue := "1"
	newValue := "2"

	at.Nil(os.Setenv(key1, oldValue))

	deck.SetupEnvs(deck.Envs{key1: newValue, key2: newValue})

	v1, v2 := SomeFunction(key1, key2)

	at.Equal(newValue, v1)
	at.Equal(newValue, v2)

	deck.TeardownEnvs()

	at.Equal(oldValue, os.Getenv(key1))
	at.Equal("", os.Getenv(key2))
}

func SomeFunction(k1, k2 string) (string, string){
	return os.Getenv(k1), os.Getenv(k2)
}

cobra.Command

Use RunCobraCmd to test a cobra command.

import (
	"github.com/go-dawn/pkg/deck"
	"github.com/stretchr/testify/assert"
)

func TestRunCobraCmd(t *testing.T) {
	at := assert.New(t)

	cmd := &cobra.Command{
		Use: "test",
		Run: func(cmd *cobra.Command, args []string) {
			cmd.Printf("%v", args)
		},
	}

	out, err := deck.RunCobraCmd(cmd, "cobra")

	at.Nil(err)
	at.Equal("[cobra]", out)
}

httptest

Use SetupServer to register fiber routes and get an *httptest.Expect instance as e. Next make request by e and finally do assertion with several helper functions.

import (
	"testing"

	"github.com/gavv/httpexpect/v2"
	"github.com/go-dawn/dawn/fiberx"
	"github.com/go-dawn/pkg/deck"
	"github.com/gofiber/fiber/v2"
)

func Test_Fiber_Routes(t *testing.T) {
	e := deck.SetupServer(t, func(app *fiber.App) {
		app.Get("/", func(c *fiber.Ctx) error {
			return fiberx.Message(c, "test")
		})
	})

	resp := e.GET("/").Expect()

	deck.AssertRespStatus(resp, fiber.StatusOK)
	deck.AssertRespCode(resp, 200)
	deck.AssertRespMsg(resp, "test")
	deck.AssertRespMsgContains(resp, "es")

	data := deck.Expected{
		Status:  500,
		Code:    500,
		Msg:     "error",
		Contain: false,
	}

	e = deck.SetupServer(t, func(app *fiber.App) {
		app.Get("/data", func(c *fiber.Ctx) error {
			return fiberx.Data(c, data)
		})
	})

	resp2 := e.GET("/data").Expect()

	deck.AssertRespData(resp2, data)
	deck.AssertRespDataCheck(resp2, func(v *httpexpect.Value) {
		obj := v.Object()
		obj.ValueEqual("Status", 500)
		obj.ValueEqual("Code", 500)
		obj.ValueEqual("Msg", "error")
		obj.ValueEqual("Contain", false)
	})
}

gorm

Use SetupGormDB to get a *gorm.DB instance as gdb and passed in models will be auto migrated. gdb is driven by an in-memory sqlite db.

import (
	"testing"

	"github.com/go-dawn/pkg/deck"
    "github.com/stretchr/testify/assert"
    "gorm.io/gorm"
)

type Fake struct {
	gorm.Model
	F string
}

func Test_DryRunSession(t *testing.T) {
	s := deck.DryRunSession(t)

	stat := s.Find(&Fake{}).Statement

	assert.Equal(t, "SELECT * FROM `fakes` WHERE `fakes`.`deleted_at` IS NULL", stat.SQL.String())
}

func Test_AssertDBCount(t *testing.T) {
	gdb := deck.SetupGormDB(t, &Fake{})

	deck.AssertDBCount(t, gdb.Model(&Fake{}), int64(0))
}

func Test_AssertDBHas(t *testing.T) {
	gdb := deck.SetupGormDB(t, &Fake{})

	assert.Nil(t, gdb.Create(&Fake{F: "f"}).Error)

	deck.AssertDBHas(t, gdb.Model(&Fake{}), Columns{"F": "f"})
}

func Test_AssertDBMissing(t *testing.T) {
	gdb := deck.SetupGormDB(t, &Fake{})

	deck.AssertDBMissing(t, gdb.Model(&Fake{}), Columns{"F": "f"})
}

# Functions

AssertDBCount asserts db has specific count.
AssertDBHas asserts db has data with specific query condition.
AssertDBMissing asserts db misses data with specific query condition.
AssertResp asserts response with an Expected instance.
AssertRespCode asserts response with an expected business code.
AssertRespData asserts response with an expected data.
AssertRespDataCheck asserts response with an expected data checker.
AssertRespMsg asserts response with an expected message.
AssertRespMsgContains asserts response contains an expected message.
AssertRespStatus asserts response with an expected status code.
DryRunSession gets a gorm session in dry run mode.
DumpStderr dumps output from Stderr and restores it to the original one.
DumpStdout dumps output from Stdout and restores it to the original one.
HandleCommand handles every command wanted help.
RedirectStderr mocks Stderr.
RedirectStdout mocks Stdout.
RunCobraCmd executes a cobra command and get output and error.
SetupCmd mocks ExecCommand.
SetupErrorCmd mocks ExecCommand and when running the returned command, always get an error.
SetupStderrCmd mocks ExecCommand.
SetupEnvs can override or set envs.
SetupExecLookPath mocks ExecLookPath.
SetupExecLookPathError mocks ExecLookPath and always return an error.
SetupGormDB gets gorm.DB instance.
SetupOsExit mocks OsExit.
SetupServer registers routes and gets and httpexpect.Expect instance.
TeardownCmd restores ExecCommand to the original one.
TeardownEnvs restores envs to original ones.
TeardownExecLookPath restores ExecLookPath to the original one.
TeardownOsExit restores OsExit to the original one.

# Variables

ErrLookPath means that error occurs when calling ExecLookPath.
ErrorHandler is Dawn's error handler.
ExecCommand is a wrapper for exec.Command.
ExecLookPath is a wrapper for exec.LookPath.
OsExit is a wrapper for os.Exit.
Stderr is a wrapper for os.Stderr.
Stdout is a wrapper for os.Stdout.

# Structs

DisabledGormLogger implements gorm logger interface.
Expected holds everything need to assert.

# Type aliases

Columns is a condition struct for query.
Envs is used for override or set env.