Test Flutter Facebook Firebase Login - flutter

I would like to test the facebookLogin() method on my app, but I can't set it properly.
Code reference
This is my test :
test(
"should return FirebaseUser when called loginWithFacebook",
() async {
// arrange
when(mockFacebookLogin.login()).thenAnswer((realInvocation) async => tToken);
when(FacebookAuthProvider.credential("token-id")).thenReturn(tCredential);
// act
final result = await repository.loginWithFacebook();
// assert
expect(result, Right(tFirebaseUser));
verify(mockFacebookLogin.login());
},
);
I get this error: Bad state: No method stub was called from within 'when()'. Was a real method called, or perhaps an extension method? on when(FacebookAuthProvider.credential("token-id")).thenReturn(tCredential);
I read that this error shows because I'm trying to mock a static method and I need to convert it to a non-static method.

Related

How to test a void function in Dart?

I am new to unit tests in Dart/Flutter and I would like to write a test for a void function. When functions return something I am writing a test like this:
test('Gets user save', () async {
final userSave = await mockSource!.getUserSave();
expect(userSave!.age, equals(20));
});
In such a scenario like above expect can be used since getUserSave function returns a user model.
How about checking if test passes of fails for a void/Future function like below? I can not use expect because it does not return a value.
Future<void> clearUserSave() async {
DatabaseClient mockDBClient = MockDatabaseClientImpl();
mockDBClient.clear();
}
I use flutter_test and mockito for testing.
Typically a void function will produce a side effect of some sort. When writing a test for a void function, I would check whatever state is effected by the void function before and after calling the function to be sure that the desired side effect has occurred.
In this specific case, you are calling clear on a DatabaseClient. I don't know the specifics of the DatabaseClient api, but I would construct a test where the client contains some data before calling clear, and then check that the data is no longer there after calling clear.
Something along the lines of this:
Future<void> clearUserSave() async {
DatabaseClient mockDBClient = MockDatabaseClientImpl();
mockDBClient.add(SOMEDATA);
expect(mockDBClient.hasData, true);
mockDBClient.clear();
expect(mockDBClient.hasData, false);
}
you can add nullable variable and assign variable value in method, after call method check if this varaible isNotNull
like this:
test('Gets user save', () async {
await mockSource?.getUserSave();
final userSave=mockSource.user;
expect(userSave,isNotNull );
});
testing a function that return void :
expect(
() async => await functionThatReturnsVoid(),
isA<void>(),
);

Missing stub error on mockito in flutter. Trying to use setString on mocked SharedPreferences

I'm trying to mock sharedPreferences using Mockito in my flutter project. Here is the error log.
package:mockito/src/mock.dart 190:7 Mock._noSuchMethod
package:mockito/src/mock.dart 184:45 Mock.noSuchMethod
test\feature\number_trivia\data\datasource\number_trivia_local_datasource_test.mocks.dart 67:14 MockSharedPreferences.setString
package:clean_arch_tdd/features/number_trivia/data/datasources/number_trivia_local_datasource.dart 31:30 NumberTriviaLocalDataSourceImpl.cacheLastNumberTrivia
test\feature\number_trivia\data\datasource\number_trivia_local_datasource_test.dart 51:18 main.<fn>.<fn>
MissingStubError: 'setString'
No stub was found which matches the arguments of this method call:
setString('CACHED_NUMBER_TRIVIA', '{"text":"Test trivia","number":1}')
Add a stub for this method using Mockito's 'when' API, or generate the mock for MockSharedPreferences with 'returnNullOnMissingStub: true'.
The error refer to this line of code.
local_data_source_test.dart
test('should call sharedPreferences to cache the data', () {
dataSource.cacheLastNumberTrivia(tNumberTriviaModel);
final expectedJsonString = jsonEncode(tNumberTriviaModel.toJson());
verify(mockSharedPreferences.setString(
cachedNumberTrivia, expectedJsonString));
});
local_data_source.dart
#override
Future<void> cacheLastNumberTrivia(NumberTriviaModel triviaToCache) {
return sharedPreferences.setString(
cachedNumberTrivia, jsonEncode(triviaToCache.toJson()));
}
It show that method setString from the mocked sharedPreferences is missing. I already run the pub command to generate the mocks. I also have some test case in the file that use the getString method. And it works fine.
Is there something I'm missing so I can't use the setString method? Or are there any solution to this problem?
Thx in advance.
I actually figured it out, sorry for not posting the answer immediately.
I found myself forgot to call the stub for the setString method. Here is the code.
group('cacheNumberTrivia', () {
const tNumberTriviaModel =
NumberTriviaModel(number: 1, text: 'Test trivia');
test('should call sharedPreferences to cache the data', () async {
when(mockSharedPreferences.setString(any, any))
.thenAnswer((_) async => true);
dataSource.cacheLastNumberTrivia(tNumberTriviaModel);
final expectedJsonString = jsonEncode(tNumberTriviaModel.toJson());
verify(mockSharedPreferences.setString(
cachedNumberTrivia, expectedJsonString));
});
});
The stub was actually this line:
when(mockSharedPreferences.setString(any, any))
.thenAnswer((_) async => true);
I forgot to call the when method before verifying the result with verify, hence it throws an error.

Flutter Getx Get.back() not returning value when used along with async function

I am using Getx package and I want to return a value using Get.back(result: getPhoneNumber()). But Get.back() does not work if an async function is executed before it. Below is the code snippet where handleResponse() is an async function. In addition to this, I have added a print statement to check the value of isSuccessful variable. the value it returns is true.
handleResponse async function:
In addition to this, I would like to state that when I comment the ResponseHandler().handleResponse() function, it works fine as expected.
What happens here is that the back() method seems to finish while getPhoneNumber() is yet to finish. The value passed in return is nullable, and most likely gets a null value since getPhoneNumber() is yet to finish.
What you can do here is first fetch the value from getPhoneNumber() before calling back().
var phoneNumber = await getPhoneNumber();
if(isSuccessful && phoneNumber != null){
Get.back(result: phoneNumber);
}

While the inner method async does the outer method has to be async?

I have an async method. Can I call it from an non-async method? Like the following
My method
void method() async{
await 'something'
}
Case 1
onPressed:() {
method();
}
Case 2
onPressed:() async{
await method();
}
Which of the above is correct? It seems to me two of them is OK. However, the second one I think works much more slower, am I wrong?
In general, the caller of an async function must also be asynchronous if it wants to wait for the call to complete. This makes asynchronous-ness contagious.
In your case, your async function is a "fire-and-forget" function; callers cannot wait for it to complete, so it doesn't matter. Your second case (with await method()) is wrong because you should use await only on Future/FutureOr, but method returns void, so there nothing to wait for. (The Dart analyzer would warn you about this if you have the await_only_futures lint enabled.)
You also could simplify your code further by using a tear-off instead of creating an unnecessary closure:
onPressed: method

Convert Future<List> of custom object in list of object

i need support on a problem.
I have a method of my DatabaseHelper that takes care of recovering users from my database created with SQLite.
So I created a class called DatabaseUserHelper that takes care of retrieving information.
Here is the method of my class:
Future<List> getAllUser() async {
var dbClient = await db;
var result = await dbClient.query(tableUser, columns: [columnId, columnNome, columnCognome, columnUsername]);
return result.toList();
}
My requirement is to convert the result of this method into a normal list.
Here is an example of what I would like to do with Java.
List <User> listUser = getAllUser ()
Unfortunately, however, every time I try to make this conversion I always get an error.
Is there anything I can do ?
Thank you all
You should use await keyword before calling the function getAllUser like below :
List<User> listUser = await getAllUser();
It is because your function has 'Future' keyword which means the result will be available sometime in the future. So, you should wait a bit.