Getting type 'Null' is not a subtype of type 'Future<Response>' in Flutter - flutter

I'm trying to run a text in flutter using mockito but I have been getting a error of
type 'Null' is not a subtype of type 'Future<Response>'
Below is the code
class MockClient extends Mock implements http.Client {}
void main() {
var client = MockClient();
var sut = AuthApi('http:baseUrl', client);
setUp(() {
client;
sut;
});
group('signin', () {
var credential = Credential(
type: AuthType.email,
email: 'email#email',
password: 'pass',
);
test('should return error when status is not 200', () async {
when(client.post(Uri(), body: anyNamed('body')))
.thenAnswer((_) async => http.Response('{}', 404));
var result = await sut.signIn(credential);
expect(result, isA<ErrorResult>());
});
});
}
I have tried to pass
when(client.post(any, body: anyNamed('body')))
but I got any error of: The argument type 'Null' can't be assigned to the parameter type 'Uri'

Since Mockito migrated to a null safety code, you need to Override the method with a new declaration inside the mock class. At a body of the override method call super.noSuchMethod, passing in an Invocation object which includes all of the values passed to the override, and pass a second argument to super.noSuchMethod, a value which can function as a return value.
Here is an example:
class MockClient extends Mock implements http.Client {
#override
Future<http.Response> post(Uri uri, {String body}) => super.noSuchMethod(Invocation.method(#post, [uri, body]), returnValue: http.Response('{}', 404));
}
Please note that your method parameters may be different

Related

type 'Null' is not a subtype of type 'Future<void>' when unit testing using mocktail package

how can we verify whether a method inside a function is called or not?
I have here a sample code.
class MockService extends Mock implements Service {}
class MockRepository extends Mock implements Repository {}
class Repository {
Repository({
required this.service,
});
final Service service;
Future<void> somethingFancy() async {
await service.doSomething();
}
}
class Service {
Future<void> doSomething() async {}
}
void main() {
final service = MockService();
final repository = Repository(service: service);
group('auth repository test', () {
test('test name', () async {
when(repository.somethingFancy).thenAnswer((_) => Future.value());
await repository.somethingFancy();
verify(service.doSomething).called(1);
});
});
}
if i run the test, i get this error:
type 'Null' is not a subtype of type 'Future<void>'
test/auth_repository_test.dart 20:16 MockService.doSomething
test/auth_repository_test.dart 15:19 Repository.registerUser
package:mocktail/src/mocktail.dart 210:8 when.<fn>
test/auth_repository_test.dart 29:11 main.<fn>.<fn>
===== asynchronous gap ===========================
dart:async _completeOnAsyncError
package:mocktail/src/mocktail.dart 210:8 when.<fn>
test/auth_repository_test.dart 29:11 main.<fn>.<fn>
if i change my repository variable to final repository = MockRepository();,
i cannot inject the Service class, so definitely the method inside service class wont be called. That's why if I run the this test:
void main() {
final service = MockService();
final repository = MockRepository();
group('auth repository test', () {
test('test name', () async {
when(repository.somethingFancy).thenAnswer((_) => Future.value());
await repository.somethingFancy();
verify(service.doSomething).called(1);
});
});
}
I get an error saying no matching calls
No matching calls (actually, no calls at all).
(If you called `verify(...).called(0);`, please instead use `verifyNever(...);`.)
package:test_api fail
package:mocktail/src/mocktail.dart 722:7 _VerifyCall._checkWith
package:mocktail/src/mocktail.dart 515:18 _makeVerify.<fn>
test/auth_repository_test.dart 32:13 main.<fn>.<fn>
What am I doing wrong here? appreciate so much help.
You are mokking the wrong method in your test.
You have to mock answer Service#doSomething instead of Repository#doSimethingFancy. Check your when statement.
test('test name', () async {
when(service.doSomething()).thenAnswer((_) => Future.value());
await repository.somethingFancy();
verify(service.doSomething).called(1);
});

Getting type 'Null' is not a subtype of type 'Future<Info>' in type cast in flutter unit testing using mockito

I have generated mock class for my store and repository class using #GenerateMocks as below::
#GenerateMocks([],customMocks: [
MockSpec<MyStore>(as: #MockMyStore, returnNullOnMissingStub: true),
MockSpec<MyRepository>(as: #MockMyRepository, returnNullOnMissingStub: true),
])
this has automatically created a test.mocks file for both store and repository class but while writing unit testing I am getting error: 'Null' is not a subtype of type 'Future' in type cast.
The test cases I have written as below:
test('call api successfully', () async {
when(mockStore.calApi()).thenAnswer((realInvocation) => Future.value());
expect(await store.calApi(), true);
});
//MyStore class
class MyStore = _MyStore with _$MyStore;
abstract class _MyStore with Store {
late MyRepository _repository;
_MyStore(MyStore repository)
: this._repository = repository;
Future<bool> callApi() async {
final isInternet = await Util.checkInternetAndShowDialog(context);
if (isInternet) {
final future = _repository.callApi();
var res = await future;
return true;
}
return false;
}
}
Can any one help me to resolve this issue, why I am receiving 'Null' subtype error and pass the test cases in flutter. I shall be thankful for this.

How to explicitly return `void`?

One flutter package has this kind of data requesting workflow:
final cancelListening = await request(
query: query,
onResponse: (response) {
streamController.add(response);
cancelListening(); // I need to cancel it here;
},
);
But this way I obviously have the error: cancelListening can't be referenced before it is declared. As request() returns Future<void Function()> I can do this:
void Function() cancelListening = () {};
cancelListening = await request(
...
And I got Omit type annotations for local variables.dart(omit_local_variable_types).
So, I write this way:
var cancelListening = () {}
cancelListening = await request(
...
But now cancelListening is Null Function() and I'm getting A value of type 'void Function()' can't be assigned to a variable of type 'Null Function()'.
So my questions is:
Is there is a way to explicitly return void in dart? Something like () => Void();
Should I simply ignore this linter rule or there is better way to handle this situation?
Thanks.
You might want to setup an intermediary function to call the received callback. VoidCallback should be a type for functions that specifically return void, instead of null.
VoidCallback? cancelListening;
void stopListening() {
cancelListening?.call();
}
void listen() async {
cancelListening = await request(
query: query,
onResponse: (response) {
streamController.add(response);
stopListening();
},
);
}
Optionally, instead of making cancelListening nullable, you could use the late keyword.
late VoidCallback cancelListening;
void stopListening() {
cancelListening(); // No optional operator `?` needed.
}

type 'Null' is not a subtype of type 'Future<Response>' when testing mocked http client with Mocktail

I have written a test for a simple HTTP get using Mocktail to mock the HTTP client. When I call the get method in the test I receive "type 'Null' is not a subtype of type 'Future'".
Anyone any idea why this might be?
Here is the test:
class MockHttpClient extends Mock implements http.Client {}
void main() {
late IdRemoteDataSourceImpl dataSource;
late MockHttpClient mockHttpClient;
setUp(
() {
mockHttpClient = MockHttpClient();
dataSource = IdRemoteDataSourceImpl(client: mockHttpClient);
},
);
group('Get id', () {
test(
'when response code is 200',
() async {
final url = Uri.parse('https://api.test.com/');
const tUsername = 'username';
final accountJson = json.decode(
fixture('account.json'),
// ignore: avoid_as
) as Map<String, dynamic>;
final tIdModel = IdModel.fromJson(accountJson);
// arrange
when(() => mockHttpClient.get(url))
.thenAnswer((_) async => http.Response(
fixture('account.json'),
200,
));
// act
final testResult = await dataSource.getId(tUsername);
// assert
// expect(testResult, tIdModel);
},
);
});
}
The error occurs when the following line runs:
final testResult = await dataSource.getId(tUsername);
Code being tested:
import 'dart:convert';
import 'package:http/http.dart' as http;
class IdModel {
IdModel({required this.id});
final String id;
factory IdModel.fromJson(Map<String, dynamic> json) {
return IdModel(id: json['id'].toString());
}
}
abstract class IdRemoteDataSource {
Future<IdModel> getId(String username);
}
class IdRemoteDataSourceImpl implements IdRemoteDataSource {
IdRemoteDataSourceImpl({required this.client});
final http.Client client;
#override
Future<IdModel> getId(String username) async {
final url = Uri.parse('https://api.test.com/query?username=$username');
final response = await client.get(url);
// ignore: avoid_as
final responseJson = json.decode(response.body) as Map<String, dynamic>;
return IdModel.fromJson(responseJson);
}
}
Error type 'Null' is not a subtype of type 'Future'... occurs when you call method that has not been implemented for mock object or there are different parameters passed to it.
In your code you passed different url parameter to get(...) method. Http client mock waiting for 'https://api.test.com/' but actually 'https://api.test.com/query?username=$username' has been passed.
You have two options to solve it.
Pass the same url to mocked method from when(...) that will be passed during test:
const tUsername = 'username';
final url = Uri.parse('https://api.test.com/query?username=$tUsername');
...
// arrange
when(() => mockHttpClient.get(url))
.thenAnswer((_) async => http.Response(
fixture('account.json'),
200,
),
);
Use any matcher (if you don't care which parameter passed):
registerFallbackValue(Uri.parse(''));
...
when(() => mockHttpClient.get(any()))
.thenAnswer((_) async => http.Response(
fixture('account.json'),
200,
),
);

How to mock a future method and not get type 'Null' is not a subtype of type 'Future<>' in flutter

I want to mock this class and this specific method
class FeedApiService extends ApiService {
Future<FeedResponse> fetchFeed(Map<String, String> params) async {
...
}
...
}
My unit test is like this
class FeedApiServiceMock extends Mock implements FeedApiService {}
void main() {
test('..', () {
FeedApiServiceMock feedApiServiceMock = FeedApiServiceMock();
when(feedApiServiceMock.fetchFeed({})).thenAnswer(
(_) => Future.value(FeedResponse(items: 1)),
);
expect(await feedApiServiceMock.fetchFeed({}).items, 1);
});
}
I just want to see that fetch feed is mocked correctly, but I'm getting this error:
type 'Null' is not a subtype of type 'Future<FeedResponse>'
See if adding async in both the test and thenAnswer method solves the problem.
void main() {
test('..', () async{
FeedApiServiceMock feedApiServiceMock = FeedApiServiceMock();
when(feedApiServiceMock.fetchFeed({})).thenAnswer(
(_) async=> Future.value(FeedResponse(items: 1)),
);
expect(await feedApiServiceMock.fetchFeed({}).items, 1);
});
}