Skip to content

Commit 799dbfe

Browse files
authored
Merge pull request #132 from anastasiamac/stub-check-calls-without-order
Stub check calls without order. All current methods on testing Stub assume that the order of calls matters. However, there are situations where we only care about the fact that the calls where made, not in what order they were made. For example, intermittent failures in https://bugs.launchpad.net/juju/+bug/1742222 specifically occur because we expect the calls to have been made but the calls in asynchronous system can be made in any order. This PR adds a method that allows to check that the expected calls where made, not when they were made.
2 parents 2fe0e88 + c4ba176 commit 799dbfe

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

stub.go

+26
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package testing
55

66
import (
77
"fmt"
8+
"reflect"
89
"sync"
910

1011
jc "github.com/juju/testing/checkers"
@@ -193,6 +194,31 @@ func (f *Stub) CheckCalls(c *gc.C, expected []StubCall) {
193194
c.Check(f.calls, jc.DeepEquals, expected)
194195
}
195196

197+
// CheckCallsUnordered verifies that the history of calls on the stub's methods
198+
// contains the expected calls. The receivers are not checked. If they
199+
// are significant then check Stub.Receivers separately.
200+
// This method explicitly does not check if the calls were made in order, just
201+
// whether they have been made.
202+
func (f *Stub) CheckCallsUnordered(c *gc.C, expected []StubCall) {
203+
// Take a copy of all calls made to the stub.
204+
calls := f.calls[:]
205+
checkCallMade := func(call StubCall) {
206+
for i, madeCall := range calls {
207+
if reflect.DeepEqual(call, madeCall) {
208+
// Remove found call from the copy of all-calls-made collection.
209+
calls = append(calls[:i], calls[i+1:]...)
210+
break
211+
}
212+
}
213+
}
214+
215+
for _, call := range expected {
216+
checkCallMade(call)
217+
}
218+
// If all expected calls were made, our resulting collection should be empty.
219+
c.Check(calls, gc.DeepEquals, []StubCall{})
220+
}
221+
196222
// CheckCall checks the recorded call at the given index against the
197223
// provided values. If the index is out of bounds then the check fails.
198224
// The receiver is not checked. If it is significant for a test then it

stub_test.go

+38
Original file line numberDiff line numberDiff line change
@@ -430,3 +430,41 @@ func (s *stubSuite) TestCheckNoCalls(c *gc.C) {
430430
c.ExpectFailure(`the "standard" Stub.CheckNoCalls call should fail here`)
431431
s.stub.CheckNoCalls(c)
432432
}
433+
434+
func (s *stubSuite) TestMethodCallsUnordered(c *gc.C) {
435+
s.stub.MethodCall(s.stub, "Method1", 1, 2, 3)
436+
s.stub.AddCall("aFunc", "arg")
437+
s.stub.MethodCall(s.stub, "Method2")
438+
439+
s.stub.CheckCallsUnordered(c, []testing.StubCall{{
440+
FuncName: "aFunc",
441+
Args: []interface{}{"arg"},
442+
}, {
443+
FuncName: "Method1",
444+
Args: []interface{}{1, 2, 3},
445+
}, {
446+
FuncName: "Method2",
447+
}})
448+
}
449+
450+
// This case checks that in the scenario when expected calls are
451+
// [a,b,c,c] but the calls made are actually [a,b,b,c], we fail correctly.
452+
func (s *stubSuite) TestMethodCallsUnorderedDuplicateFail(c *gc.C) {
453+
s.stub.MethodCall(s.stub, "Method1", 1, 2, 3)
454+
s.stub.MethodCall(s.stub, "Method1", 1, 2, 3)
455+
s.stub.AddCall("aFunc", "arg")
456+
s.stub.MethodCall(s.stub, "Method2")
457+
458+
s.stub.CheckCallsUnordered(c, []testing.StubCall{{
459+
FuncName: "aFunc",
460+
Args: []interface{}{"arg"},
461+
}, {
462+
FuncName: "Method1",
463+
Args: []interface{}{1, 2, 3},
464+
}, {
465+
FuncName: "Method2",
466+
}, {
467+
FuncName: "Method2",
468+
}})
469+
c.ExpectFailure("should have failed as expected calls differ from calls made")
470+
}

0 commit comments

Comments
 (0)