Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chain multiple calls with same arguments to return different results

I'm in the process of writing a Flutter app with some extensive unit test coverage.
I'm using Mockito to mock my classes.
Coming from a Java (Android) world where I can use Mockito to chain calls to return different values on subsequent calls.
I would expect this to work.

import 'package:test/test.dart';
import 'package:mockito/mockito.dart';

void main() {
  test("some string test", () {
    StringProvider strProvider = MockStringProvider();
    when(strProvider.randomStr()).thenReturn("hello");
    when(strProvider.randomStr()).thenReturn("world");

    expect(strProvider.randomStr(), "hello");
    expect(strProvider.randomStr(), "world");
  });
}

class StringProvider {
  String randomStr() => "real implementation";
}

class MockStringProvider extends Mock implements StringProvider {}

However it throws:

Expected: 'hello'
Actual:   'world'
  Which: is different.

The only working way I found that works is by keeping track myself.

void main() {
  test("some string test", () {
    StringProvider strProvider = MockStringProvider();

    var invocations = 0;
    when(strProvider.randomStr()).thenAnswer((_) {
      var a = '';
      if (invocations == 0) {
        a = 'hello';
      } else {
        a = 'world';
      }
      invocations++;
      return a;
    });

    expect(strProvider.randomStr(), "hello");
    expect(strProvider.randomStr(), "world");
  });
}

00:01 +1: All tests passed!

Is there a better way?

like image 493
timr Avatar asked Dec 22 '18 13:12

timr


People also ask

Can we mock same method twice?

We can stub a method with multiple return values for the consecutive calls. Typical use case for this kind of stubbing could be mocking iterators.

What is the difference between doReturn and thenReturn?

The parameter of doReturn is Object unlike thenReturn . So, there is no type checking in the compile time. When the type is mismatched in the runtime, there would be an WrongTypeOfReturnValue execption. doReturn(true).

What is stubbing Mockito?

A typical stub is a database connection that allows you to mimic any scenario without having a real database. A mock is a fake class that can be examined after the test is finished for its interactions with the class under test. For example, you can ask it whether a method was called or how many times it was called.

What is given in Mockito?

The Mockito library is shipped with a BDDMockito class which introduces BDD-friendly APIs. This API allows us to take a more BDD friendly approach arranging our tests using given() and making assertions using then().


1 Answers

Use a list and return the answers with removeAt:

import 'package:test/test.dart';
import 'package:mockito/mockito.dart';

void main() {
  test("some string test", () {
    StringProvider strProvider = MockStringProvider();
    var answers = ["hello", "world"];

    when(strProvider.randomStr()).thenAnswer((_) => answers.removeAt(0));

    expect(strProvider.randomStr(), "hello");
    expect(strProvider.randomStr(), "world");
  });
}

class StringProvider {
  String randomStr() => "real implementation";
}

class MockStringProvider extends Mock implements StringProvider {}
like image 175
attdona Avatar answered Nov 27 '22 11:11

attdona