Skip to content

Commit

Permalink
feat: Conditionally enable/disable Unset call
Browse files Browse the repository at this point in the history
Consider the following example test scenario:
The goal is to test http server API. The test may set up a local http
server, database and mocks to 3rd party services. Since the tests are
calling mocked server it may be useful to use mock `EXPECT()` calls.
Test structure:
1. Setup local server, database and mocks
2. Mock 3rd party service calls
3. Send request to local server
4. Assert response
5. Verify side effects - execute database query

As an enhancement, such tests can easily be called against deployed
application, by simply replacing server and database URLs.
The only catch are mocked calls, which won't be executed, since the
request is sent to a remote server.

In such case it may be possible to call `Unset()` method with
`WithUnsetToggle` option, which value is set based on the current
environment. For example:
```go
func Env() mock.UnsetOption {
    if os.Getenv("local") {
        return mock.WithUnsetToggle(false)
    }
    return mock.WithUnsetToggle(true)
}

// In test ...
func TestAPI(t *testing.T) {
    // setup server, database and mocks
    mock.Call3rdParty(ctx, argument).Return(nil).Unset(Env())

    response := client.Post(request)
    // assertions and database query
}
```

In the above example, if environment is "local" Unset will be disabled,
meaning that all mocks will execute.
If environment is other than "local" the Unset will be enabled, meaning
that mocks will not be called.

Signed-off-by: Piotr Persona <[email protected]>
  • Loading branch information
piotrpersona committed May 30, 2024
1 parent 1b4fca7 commit 035a12b
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 1 deletion.
41 changes: 40 additions & 1 deletion mock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,49 @@ func (c *Call) On(methodName string, arguments ...interface{}) *Call {
return c.Parent.On(methodName, arguments...)
}

// unsetConfiguration stores Unset method call configuration.
type unsetConfiguration struct {
enabled bool
}

// UnsetOption will allow to configure Unset method invocation.
type UnsetOption func(*unsetConfiguration)

// WithUnsetToggle will configure unset value. If enabled == false the Unset
// function will not be called. Default: true - the Unset will be called.
// This option may be used to conditionally enable or disable mock calls.
func WithUnsetToggle(enabled bool) UnsetOption {
return func(uc *unsetConfiguration) {
uc.enabled = enabled
}
}

// WithUnsetEnabled is shorthand for WithUnsetToggle(true).
func WithUnsetEnabled() UnsetOption {
return func(uc *unsetConfiguration) {
uc.enabled = true
}
}

// WithUnsetEnabled is shorthand for WithUnsetToggle(false).
func WithUnsetDisabled() UnsetOption {
return func(uc *unsetConfiguration) {
uc.enabled = false
}
}

// Unset removes a mock handler from being called.
//
// test.On("func", mock.Anything).Unset()
func (c *Call) Unset() *Call {
func (c *Call) Unset(options ...UnsetOption) *Call {
configuration := &unsetConfiguration{enabled: true}
for _, option := range options {
option(configuration)
}
if !configuration.enabled {
return c
}

var unlockOnce sync.Once

for _, arg := range c.Arguments {
Expand Down
29 changes: 29 additions & 0 deletions mock/mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,35 @@ func Test_Mock_Unset_WithFuncPanics(t *testing.T) {
})
}

func Test_Mock_Unset_WithUnsetToggle_Option(t *testing.T) {
// make a test impl object
var mockedService = new(TestExampleImplementation)
mockedService.On("TheExampleMethod", 1).
Unset(WithUnsetToggle(true))
assert.Len(t, mockedService.ExpectedCalls, 0)

mockedService.On("TestExampleMethod", 1).
Unset(WithUnsetToggle(false))
assert.Len(t, mockedService.ExpectedCalls, 1)
}

func Test_Mock_Unset_WithUnsetEnabled_Option(t *testing.T) {
// make a test impl object
var mockedService = new(TestExampleImplementation)
mockedService.On("TheExampleMethod", 1).
Unset(WithUnsetEnabled())

assert.Len(t, mockedService.ExpectedCalls, 0)
}

func Test_Mock_Unset_WithUnsetDisabled_Option(t *testing.T) {
// make a test impl object
var mockedService = new(TestExampleImplementation)
mockedService.On("TheExampleMethod", 1).
Unset(WithUnsetDisabled())
assert.Len(t, mockedService.ExpectedCalls, 1)
}

func Test_Mock_Return(t *testing.T) {

// make a test impl object
Expand Down

0 comments on commit 035a12b

Please sign in to comment.