Skip to content

Commit

Permalink
Add T object and Test method to Mock
Browse files Browse the repository at this point in the history
This makes is possible to fail the test instead of panicing in case
that the method was called with unexpected arguments.

Fixes #489

mock: change field 'T' to be private field 'test'
mock_test: MockTestingT not using Mock anymore
  • Loading branch information
posener authored and ernesto-jimenez committed Mar 19, 2018
1 parent 20dae58 commit 33951ec
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 5 deletions.
31 changes: 28 additions & 3 deletions mock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ type Mock struct {
// Holds the calls that were made to this mocked object.
Calls []Call

// test is An optional variable that holds the test struct, to be used when an
// invalid mock call was made.
test TestingT

// TestData holds any data that might be useful for testing. Testify ignores
// this data completely allowing you to do whatever you like with it.
testData objx.Map
Expand All @@ -213,6 +217,27 @@ func (m *Mock) TestData() objx.Map {
Setting expectations
*/

// Test sets the test struct variable of the mock object
func (m *Mock) Test(t TestingT) {
m.mutex.Lock()
defer m.mutex.Unlock()
m.test = t
}

// fail fails the current test with the given formatted format and args.
// In case that a test was defined, it uses the test APIs for failing a test,
// otherwise it uses panic.
func (m *Mock) fail(format string, args ...interface{}) {
m.mutex.Lock()
defer m.mutex.Unlock()

if m.test == nil {
panic(fmt.Sprintf(format, args...))
}
m.test.Errorf(format, args...)
m.test.FailNow()
}

// On starts a description of an expectation of the specified method
// being called.
//
Expand Down Expand Up @@ -329,14 +354,14 @@ func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Argumen
m.mutex.Unlock()

if closestCall != nil {
panic(fmt.Sprintf("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n\n%s\nDiff: %s",
m.fail("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n\n%s\nDiff: %s",
callString(methodName, arguments, true),
callString(methodName, closestCall.Arguments, true),
diffArguments(closestCall.Arguments, arguments),
strings.TrimSpace(mismatch)),
strings.TrimSpace(mismatch),
)
} else {
panic(fmt.Sprintf("\nassert: mock: I don't know what to return because the method call was unexpected.\n\tEither do Mock.On(\"%s\").Return(...) first, or remove the %s() call.\n\tThis method was unexpected:\n\t\t%s\n\tat: %s", methodName, methodName, callString(methodName, arguments, true), assert.CallerInfo()))
m.fail("\nassert: mock: I don't know what to return because the method call was unexpected.\n\tEither do Mock.On(\"%s\").Return(...) first, or remove the %s() call.\n\tThis method was unexpected:\n\t\t%s\n\tat: %s", methodName, methodName, callString(methodName, arguments, true), assert.CallerInfo())
}
}

Expand Down
59 changes: 57 additions & 2 deletions mock/mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ import (
"errors"
"fmt"
"regexp"
"runtime"
"sync"
"testing"
"time"

"runtime"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -93,6 +92,34 @@ func (i *TestExampleImplementation) TheExampleMethodFuncType(fn ExampleFuncType)
return args.Error(0)
}

// MockTestingT mocks a test struct
type MockTestingT struct {
logfCount, errorfCount, failNowCount int
}

const mockTestingTFailNowCalled = "FailNow was called"

func (m *MockTestingT) Logf(string, ...interface{}) {
m.logfCount++
}

func (m *MockTestingT) Errorf(string, ...interface{}) {
m.errorfCount++
}

// FailNow mocks the FailNow call.
// It panics in order to mimic the FailNow behavior in the sense that
// the execution stops.
// When expecting this method, the call that invokes it should use the following code:
//
// assert.PanicsWithValue(t, mockTestingTFailNowCalled, func() {...})
func (m *MockTestingT) FailNow() {
m.failNowCount++

// this function should panic now to stop the execution as expected
panic(mockTestingTFailNowCalled)
}

/*
Mock
*/
Expand Down Expand Up @@ -205,6 +232,34 @@ func Test_Mock_On_WithIntArgMatcher(t *testing.T) {
})
}

func TestMock_WithTest(t *testing.T) {
var (
mockedService TestExampleImplementation
mockedTest MockTestingT
)

mockedService.Test(&mockedTest)
mockedService.On("TheExampleMethod", 1, 2, 3).Return(0, nil)

// Test that on an expected call, the test was not failed

mockedService.TheExampleMethod(1, 2, 3)

// Assert that Errorf and FailNow were not called
assert.Equal(t, 0, mockedTest.errorfCount)
assert.Equal(t, 0, mockedTest.failNowCount)

// Test that on unexpected call, the mocked test was called to fail the test

assert.PanicsWithValue(t, mockTestingTFailNowCalled, func() {
mockedService.TheExampleMethod(1, 1, 1)
})

// Assert that Errorf and FailNow were called once
assert.Equal(t, 1, mockedTest.errorfCount)
assert.Equal(t, 1, mockedTest.failNowCount)
}

func Test_Mock_On_WithPtrArgMatcher(t *testing.T) {
var mockedService TestExampleImplementation

Expand Down

0 comments on commit 33951ec

Please sign in to comment.