I have a mock for a SharedPreferencesService
that is supposed to return a true/false depending on whether it's the user's first time using the app.
I have a parameter in my method to initialize the mock service to set the value as true/false, with a default of true, but it just seems to always be returning the default value.
I suspect this might be an issue with how my locator is set up (I'm using GetIt locator to initialize my services).
I'm using Mocktail for mocking my services.
I'm using a GetIt locator
for dependency injection:
Here is my locator instance (in the main code):
GetIt locator = GetIt.instance;
void setupLocator() {
locator.registerLazySingleton(() => AuthenticationService());
locator.registerLazySingleton(() => FirestoreUserService());
locator.registerLazySingleton(() => FirestoreGoalService());
locator.registerLazySingleton(() => stacked_services.NavigationService());
locator.registerLazySingleton(() => SharedPreferencesService());
locator.registerLazySingleton(() => stacked_services.DialogService());
locator.registerLazySingleton(() => LoginAndUserService());
}
And here's how SharedPreferencesService is called in my system under test (SUT):
class LoginAndUserService {
// MARK
// Services
final SharedPreferencesService _prefs = locator<SharedPreferencesService>();
My test group registers services in the setUp method:
void main() {
group('LoginAndUserService Tests -', () {
late LoginAndUserService sut;
setUp(() {
registerServices();
sut = LoginAndUserService();
});
Register services calls this:
void registerServices() {
getAndRegisterSharedPreferencesServiceMock();
}
And that operates as follows:
SharedPreferencesServiceMock getAndRegisterSharedPreferencesServiceMock(
{bool? firstTimeUsage}) {
removeRegistrationIfExists<SharedPreferencesService>();
var service = SharedPreferencesServiceMock();
when(() => service.firstTimeUsingApp()).thenAnswer((_) async {
if (firstTimeUsage == null) {
return true;
} else {
return firstTimeUsage;
}
});
when(() => service.firstTimeAppUsageComplete()).thenAnswer((_) async => true);
locator.registerSingleton<SharedPreferencesService>(service);
return service;
}
So, by default, it is registering a version of this SharedPreferencesServiceMock that has the default value of true
.
However, in my test, I call this specific method again, to re-register the sharedPreferencesServiceMock with a firstTimeUsage value of false
.
Here is my test - it should recreate the SharedPreferencesService with a firstTimeUsage value of false.
test(
'loadAuthenticationPage - firstTimeUsingApp set to value in sharedprefs',
() async {
// ARRANGE
var service =
getAndRegisterSharedPreferencesServiceMock(firstTimeUsage: false);
// ACT
await sut.loadAuthenticationPage();
bool firstTimeUsingAppValue = await service.firstTimeUsingApp();
print('SharedPrefs firstTimeUsingApp is $firstTimeUsingAppValue');
var result = sut.firstTimeUsingApp;
// ASSERT
expect(result, false);
});
However, both the print statement and the result are coming back as true
so somehow the mock service must not be returning that value appropriately. Any ideas what I might be missing?
I've found two solutions:
First, make sure I initialize the SUT after I update the locator.
test(
'loadAuthenticationPage - firstTimeUsingApp set to value in sharedprefs',
() async {
// ARRANGE
var service =
getAndRegisterSharedPreferencesServiceMock(firstTimeUsage: false);
// sut is specified in the group - I need to re-initialize this after the locator.
sut = LoginAndUserService();
// ACT
await sut.loadAuthenticationPage();
bool firstTimeUsingAppValue = await service.firstTimeUsingApp();
print('SharedPrefs firstTimeUsingApp is $firstTimeUsingAppValue');
var result = sut.firstTimeUsingApp;
// ASSERT
expect(result, false);
});
The other is just overriding the when
response directly in my test, instead of in my loading of the locator.
I'm still interested in whether there's a way to do this in the loads of my locator, but this seems to work properly.
test(
'loadAuthenticationPage - firstTimeUsingApp set to value in sharedprefs',
() async {
// ARRANGE
var service = locator<SharedPreferencesService>();
// update my when response manually here.
when(() => service.firstTimeUsingApp()).thenAnswer((_) async => false);
// ACT
await sut.loadAuthenticationPage();
bool firstTimeUsingAppValue = await service.firstTimeUsingApp();
print('SharedPrefs firstTimeUsingApp is $firstTimeUsingAppValue');
var result = sut.firstTimeUsingApp;
// ASSERT
expect(result, false);
});