Chain multiple calls with same arguments to return different results

1,521

Solution 1

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 {}

Solution 2

You're not forced to call when in the start of the test:

StringProvider strProvider = MockStringProvider();
when(strProvider.randomStr()).thenReturn("hello");
expect(strProvider.randomStr(), "hello");

when(strProvider.randomStr()).thenReturn("world");
expect(strProvider.randomStr(), "world");

Mockito is dart has a different behavior. Subsequent calls override the value.

Share:
1,521
timr
Author by

timr

Freelance Mobile Developer @ Tapped BV Mainly Kotlin/Dart

Updated on December 08, 2022

Comments

  • timr
    timr over 1 year

    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?

  • timr
    timr over 5 years
    This seems like a reasonable alternative. Thanks