Skip to content

Commit

Permalink
Move tests to the _test packages
Browse files Browse the repository at this point in the history
Tests are moved to the `_test` package for improved encapsulation. Private
functions within the target package are not exposed during testing.
Additionally, mock files are suffixed with `_test` to be automatically
ignored by coverage tools. The exception to this rule is tests related
to the database. These tests remain in the same package as the database
functions to allow access to the internal database handle for checking
the state of the database.
  • Loading branch information
Lai-YT committed Apr 7, 2024
1 parent 3e9cfd0 commit 5cb6461
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 38 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ PACKAGES ?= $(shell $(GO) list ./...)
GOFILES := $(shell find . -name "*.go")
TESTTAGS ?= "-test.shuffle=on"
COVERPROFILE ?= coverage.out
COVEREXCLUDE ?= "mock"
COVEREXCLUDE ?= "$$^"

.PHONY: test
test:
Expand Down
32 changes: 17 additions & 15 deletions core/core_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package core
package core_test

import (
"errors"
"io"
"os"
"testing"

core "todolist/core"

log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
Expand All @@ -23,13 +25,13 @@ type testEnv struct {
t *testing.T
ctrl *gomock.Controller
mockAccessor *MockStorageAccessor
core *TheCore
core *core.TheCore
}

func newTestEnv(t *testing.T) *testEnv {
ctrl := gomock.NewController(t)
mockAccessor := NewMockStorageAccessor(ctrl)
theCore := NewCore(mockAccessor)
theCore := core.NewCore(mockAccessor)
return &testEnv{t, ctrl, mockAccessor, theCore}
}

Expand All @@ -39,14 +41,14 @@ func TestCreateItem(t *testing.T) {
e := newTestEnv(t)
e.mockAccessor.EXPECT().
Create(gomock.Any()).
DoAndReturn(func(item *TodoItem) (int, error) {
DoAndReturn(func(item *core.TodoItem) (int, error) {
id := 1
item.ID = id
return id, nil
})

// act
want := TodoItem{ID: 1, Description: "some description", Completed: false}
want := core.TodoItem{ID: 1, Description: "some description", Completed: false}
got := e.core.CreateItem(want.Description)

// assert
Expand All @@ -59,8 +61,8 @@ func TestUpdateItem(t *testing.T) {
e := newTestEnv(t)
e.mockAccessor.EXPECT().
Read(gomock.Any()).
DoAndReturn(func(func(TodoItem) bool) []TodoItem {
return []TodoItem{
DoAndReturn(func(func(core.TodoItem) bool) []core.TodoItem {
return []core.TodoItem{
{ID: 1, Description: "some description", Completed: false},
}
})
Expand All @@ -69,7 +71,7 @@ func TestUpdateItem(t *testing.T) {
Return(nil)

// act
want := TodoItem{ID: 1, Description: "some description", Completed: true}
want := core.TodoItem{ID: 1, Description: "some description", Completed: true}
got, err := e.core.UpdateItem(want.ID, want.Completed)

// assert: the item should be updated and returned without error
Expand All @@ -84,8 +86,8 @@ func TestUpdateItemNotFound(t *testing.T) {
e := newTestEnv(t)
e.mockAccessor.EXPECT().
Read(gomock.Any()).
DoAndReturn(func(func(TodoItem) bool) []TodoItem {
return []TodoItem{}
DoAndReturn(func(func(core.TodoItem) bool) []core.TodoItem {
return []core.TodoItem{}
})

// act
Expand All @@ -94,7 +96,7 @@ func TestUpdateItemNotFound(t *testing.T) {
_, err := e.core.UpdateItem(id, completed)

// assert: an error should be returned
assert.IsType(t, TodoItemNotFoundError{}, err)
assert.IsType(t, core.TodoItemNotFoundError{}, err)
}

// TestDeleteItem Given an id and the storage accessor returns no error, when DeleteItem is called, then no error is returned.
Expand Down Expand Up @@ -134,20 +136,20 @@ func TestDeleteItemError(t *testing.T) {
func TestGetItems(t *testing.T) {
// arrange
e := newTestEnv(t)
mockItems := [2]TodoItem{
mockItems := [2]core.TodoItem{
{ID: 1, Description: "some description", Completed: false},
{ID: 2, Description: "another description", Completed: true},
}
e.mockAccessor.EXPECT().
Read(gomock.Any()).
DoAndReturn(func(func(TodoItem) bool) []TodoItem {
DoAndReturn(func(func(core.TodoItem) bool) []core.TodoItem {
// With completed = false.
return []TodoItem{mockItems[0]}
return []core.TodoItem{mockItems[0]}
})

// act
completed := false
want := []TodoItem{mockItems[0]}
want := []core.TodoItem{mockItems[0]}
got := e.core.GetItems(completed)

// assert
Expand Down
18 changes: 10 additions & 8 deletions core/mock_storage.go → core/mock_storage_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 12 additions & 11 deletions endpoint/endpoint_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package endpoint
package endpoint_test

import (
"encoding/json"
Expand All @@ -15,6 +15,7 @@ import (
"testing"

"todolist/core"
"todolist/endpoint"

"github.com/gorilla/mux"
log "github.com/sirupsen/logrus"
Expand All @@ -40,7 +41,7 @@ type testEnv struct {
func newTestEnv(t *testing.T) *testEnv {
ctrl := gomock.NewController(t)
mockCore := NewMockCore(ctrl)
SetCore(mockCore)
endpoint.SetCore(mockCore)
return &testEnv{
t: t,
router: mux.NewRouter(),
Expand Down Expand Up @@ -76,7 +77,7 @@ func TestHealthz(t *testing.T) {
// arrange
e := newTestEnv(t)
pattern := "/healthz"
e.router.HandleFunc(pattern, Healthz)
e.router.HandleFunc(pattern, endpoint.Healthz)

// act: make a request to the /healthz endpoint
request, _ := http.NewRequest(http.MethodGet, pattern, nil)
Expand All @@ -98,7 +99,7 @@ func TestCreateItem(t *testing.T) {
// arrange
e := newTestEnv(t)
pattern := "/todo"
e.router.HandleFunc(pattern, CreateItem)
e.router.HandleFunc(pattern, endpoint.CreateItem)
testDescription := "test"
e.mockCore.EXPECT().
CreateItem(testDescription).
Expand All @@ -125,7 +126,7 @@ func TestUpdateItem(t *testing.T) {
// arrange
e := newTestEnv(t)
pattern := "/todo/{id}"
e.router.HandleFunc(pattern, UpdateItem)
e.router.HandleFunc(pattern, endpoint.UpdateItem)
testID := 1
testCompleted := true
e.mockCore.EXPECT().
Expand Down Expand Up @@ -153,7 +154,7 @@ func TestUpdateItemError(t *testing.T) {
// arrange
e := newTestEnv(t)
pattern := "/todo/{id}"
e.router.HandleFunc(pattern, UpdateItem)
e.router.HandleFunc(pattern, endpoint.UpdateItem)
e.mockCore.EXPECT().
UpdateItem(gomock.Any(), gomock.Any()).
Return(core.TodoItem{} /* dummy */, errors.New("test error"))
Expand Down Expand Up @@ -183,7 +184,7 @@ func TestDeleteItem(t *testing.T) {
// arrange
e := newTestEnv(t)
pattern := "/todo/{id}"
e.router.HandleFunc(pattern, DeleteItem)
e.router.HandleFunc(pattern, endpoint.DeleteItem)
testID := 1
e.mockCore.EXPECT().
DeleteItem(testID).
Expand All @@ -206,7 +207,7 @@ func TestDeleteItemError(t *testing.T) {
// arrange
e := newTestEnv(t)
pattern := "/todo/{id}"
e.router.HandleFunc(pattern, DeleteItem)
e.router.HandleFunc(pattern, endpoint.DeleteItem)
e.mockCore.EXPECT().
DeleteItem(gomock.Any()).
Return(errors.New("test error"))
Expand All @@ -231,7 +232,7 @@ func TestGetItemsCompleted(t *testing.T) {
// arrange
e := newTestEnv(t)
pattern := "/todo"
e.router.HandleFunc(pattern, GetItems)
e.router.HandleFunc(pattern, endpoint.GetItems)
todoItems := []core.TodoItem{
{ID: 1, Description: "test1", Completed: true},
{ID: 3, Description: "test3", Completed: true},
Expand All @@ -257,7 +258,7 @@ func TestGetItemIncomplete(t *testing.T) {
// arrange
e := newTestEnv(t)
pattern := "/todo"
e.router.HandleFunc(pattern, GetItems)
e.router.HandleFunc(pattern, endpoint.GetItems)
todoItems := []core.TodoItem{
{ID: 2, Description: "test2", Completed: false},
{ID: 4, Description: "test4", Completed: false},
Expand All @@ -283,7 +284,7 @@ func TestGetItemsAll(t *testing.T) {
// arrange
e := newTestEnv(t)
pattern := "/todo"
e.router.HandleFunc(pattern, GetItems)
e.router.HandleFunc(pattern, endpoint.GetItems)
todoItems := []core.TodoItem{
{ID: 1, Description: "test1", Completed: true},
{ID: 2, Description: "test2", Completed: false},
Expand Down
6 changes: 3 additions & 3 deletions endpoint/mock_core.go → endpoint/mock_core_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 5cb6461

Please sign in to comment.