I was doing some unit testing in flutter with mockito, and I feels unable to verify a method is called within another method. The code I've written so far as follows,
The class I want to test
class A {
void doSomething() {
callMe();
}
void callMe() {}
}
Mocked class
class MockA extends Mock implements A {}
The test I wrote,
test("Test method is called", () {
A a = new MockA();
a.doSomething();
verify(a.callMe()).called(1);
});
When I run the above test I am getting an error
No matching calls. All calls: MockA.doSomething()
(If you called `verify(...).called(0);`, please instead use `verifyNever(...);`.)
If i verify doSomething is called it works, but for a call on callMe within doSomething doesn't work. Is this the default behavior or am I doing something wrong? Please note I need to verify the callMe() method is called when doSomething() is called.
CodePudding user response:
You mocked A
and replaced it with MockA
. Mocks have no implementation. MockA.doSomething()
does nothing and does not and cannot call MockA.callMe()
.
That A.doSomething()
calls A.callMe()
should be considered an implementation detail of of doSomething()
; making a test rely on that would tightly couple the test to the specific implementation and would be brittle.
You can't use a mock to verify the implementation of the thing being mocked. If you want to verify the implementation of A.doSomething()
, you instead should use an actual object and verify observable properties on that object.
But if you still really want to do this, then you would need to modify A
to not call methods on itself and to instead call methods on a provided object (i.e., "dependency injection"). For example:
class A {
final late A a;
A({A? a}) {
this.a = a ?? this;
}
void doSomething() {
a.callMe();
}
void callMe() {}
}
test("Test method is called", () {
var mockA = MockA();
var actualA = A(a: mockA);
actualA.doSomething();
verify(mockA.callMe()).called(1);
});
It's a bit unusual for a class to depend on a mock of itself, however, and it would not scale if you then want to verify calls made by callMe()
.
Another approach that would scale better (but with significantly more work) would be to create your own fake class that tracks method calls:
class TrackedA implements A {
int doSomethingCallCount = 0;
int callMeCallCount = 0;
@override
void doSomething() {
doSomethingCallCount = 1;
super.doSomething();
}
@override
void callMe() {
callMeCallCount = 1;
super.callMe();
}
}
But again, that's very brittle, and I would not recommend it.