SVG
SVG

Reputation: 924

How to verify a method inside a method is called in mockito

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.

Upvotes: 5

Views: 4336

Answers (1)

jamesdlin
jamesdlin

Reputation: 90184

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 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 (not mocked) instance of A and then verify observable properties on that instance.

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.

Another approach would be to use a hybrid approach where you create your own derived class but where some of its overrides delegate to a Mock implementation. See: How can I test a method and to mock another method that are in the same class in Flutter.

Upvotes: 10

Related Questions