Mockito - stub a method after the null-safety migration
Asked Answered
S

2

13

Before the null safety I could simply mock up the sendRequest(...) method like that:

 void stubBaseRepositorySendRequestResponse(String response) {
    when(baseRepository.sendRequest(onGetData: anyNamed('onGetData')))
        .thenAnswer((_) {
      return Future<String>.value(response);
    });
  }

where the signature of this method is:

Future<T> sendRequest<T>({required Future<T> Function() onGetData})

How can this be done with the new null-safe version of mockito? Can I still maintain the generic character of this stub and allow for any arguments to be passed in?

Sweeting answered 27/4, 2021 at 20:51 Comment(0)
S
14

This can be easily done with mocktail. A lot easier, without the code gen required by mockito.

Important to import mocktail first:

import 'package:mocktail/mocktail.dart';

then create a mock of the class that we want to mock:

class MockBaseRepository extends Mock implements BaseRepository {}

void stubBaseRepositorySendRequestResponse(String response) {
when(() => baseRepository.sendRequest(
        onGetData: any(named: 'onGetData', that: isNotNull))).thenAnswer((_) {
      return Future<String>.value(response);
    });
  }
Sweeting answered 28/4, 2021 at 17:10 Comment(1)
This works perfectly in my case. Thank you!Derk
J
5

Updating stubs after mockito null-safety upgrade:

To outline the process, a stubbed class will need to be generated, which is done using build_runner package. You will need to import that class and stub required methods.

  1. Update the class - remove 'Mock' from the stub definition, because the imported stub class will start with 'Mock', eg:

class MyClass extends Mock implements MyClassBase {}

instead of


class MockMyClass extends Mock implements MyClassBase {}
  1. Before main add @GenerateMocks([MockedClass]) eg @GenerateMocks([MyClass]) (it'll require an import: import 'package:mockito/annotations.dart';)
  2. Install build_runner
  3. Generate stub class by running

flutter pub run build_runner build --delete-conflicting-outputs

  1. Import the stubbed class in your test file, which will be generated in the same directory as your test file, import will look like import '{TEST_FILE_NAME}.mocks.dart';. Now the stub class is available with the same name as given in Generate( starting with Mock, eg MockMyClass
  2. Stub required method, before the call/assertion (provide parameters and return value):
    when(mockMyClass.someFancyMethod(any, any))
        .thenAnswer((_) => Future.value(null));

PS

Was having issues mocking NavigatorObserver this way, the error I got:

The following MissingStubError was thrown building IconTheme(color: Color(0xdd000000)): 'navigator'

Stubbing navigator with NavigatorState didn't help, I guess it's related to context propagation.

I worked around it by using the following non-null safe way, as specified in mockito's null-safety guideline:

@GenerateMocks([], 
  customMocks: [
    MockSpec<NavigatorObserver>(returnNullOnMissingStub: true)
  ])

after that run

flutter pub run  build_runner build --delete-conflicting-outputs

It'll yield MockNavigatorObserver available through the import of *.mocks.dart file (mentioned above). Of course, since it's generated by mockito need to remove any custom definitions of that class.

Jaquesdalcroze answered 15/7, 2021 at 11:49 Comment(2)
This solved the issue I had been trying to debug for hours. Thanks a lot!Inconsonant
Step 1 doesn't seem quite right; you shouldn't need to explicitly declare any classes that extend Mock at all. The code generation step should generate the classes for you.Hyades

© 2022 - 2024 — McMap. All rights reserved.