Closed elianortega closed 3 years ago
Hi @elian-ortega π Thanks for opening an issue!
As the error indicates, you need to register fallback values for the bloc event and state. You can add these following lines to your test:
class FakeQrGeneratorEvent extends Fake implements QrGeneratorEvent {}
class FakeQrGeneratorState extends Fake implements QrGeneratorState {}
void main() {
setUpAll(() {
registerFallbackValue<QrGeneratorEvent>(FakeQrGeneratorEvent());
registerFallbackValue<QrGeneratorState>(FakeQrGeneratorState());
});
...
}
Hope that helps π
It works! Thank you very much @felangel!
In my case it was only the state because I'm using cubit, so I did this to fix it:
void main() {
setUpAll(() {
registerFallbackValue<QrGeneratorState>(FakeQrGeneratorState());
registerFallbackValue<scanner_s.QrScannerState>(FakeQrScannerState());
});
...
}
Something more I just have one question, Why is it necessary to register the fall back value and mocking the state and event ?
Hi @felangel,
I still got an error if I use cubit that emits enum
even though we already added registerFallbackValue(AppTab)
(AppTab
is an enum
).
I can't create FakeAppTab
because I can't implement enum
Is there any workaround that does not include changing enum
to FooState
?
Hi @tijanirf π You can just registerFallback with a real enum value in this case:
registerFallbackValue(AppTab.home);
Hope that helps π
Hi @felangel
Can you please describe what is the use of registerFallbackValue
Hey @shan-shaji straight from the docs:
/// Allows [any] and [captureAny] to be used on parameters of type [T].
///
/// It is necessary for tests to call [registerFallbackValue] before using
/// [any]/[captureAny] because otherwise it would not be possible to assign
/// [any]/[captureAny] as value to a non-nullable parameter.
///
/// Mocktail comes with already pre-registered values, for types such as [int],
/// [String] and more.
///
/// Once registered, a value cannot be unregistered, even when using
/// [resetMocktailState].
///
/// It is a good practice to create a function shared between all tests that
/// calls [registerFallbackValue] with various types used in the project.
In fewer word any()
can substitute any basic data type: int, string, etc. But any()
have no idea of the existence of a complex model from your project. So by registering a fallbackValue you give the ability to any()
method to substitute the new model/data type you have registered.
Thank you @elianmortega ,
So any()
to work properly i need to register model/data type
defined in my project.
Yes, but only the ones that will be used on the tests, there is no need on registering a model that won't be used in the test π .
Ok Thank you @elianmortega π
I have the same problem. This is my code:
class MockUserRepository extends Mock implements UserRepository {}
class MockAuthenticationBloc extends MockBloc<AuthenticationEvent, AuthenticationState> implements AuthenticationBloc {}
class FakeAuthenticationEvent extends Fake implements AuthenticationEvent {}
class FakeAuthenticationState extends Fake implements AuthenticationState {}
void main() {
MockUserRepository mockUserRepository;
MockAuthenticationBloc mockAuthenticationBloc;
setUp(() {
mockUserRepository = MockUserRepository();
mockAuthenticationBloc = MockAuthenticationBloc();
registerFallbackValue(FakeAuthenticationEvent());
registerFallbackValue(FakeAuthenticationState());
});
group('Login', () {
final username = 'someusername';
final password = 'somepassword';
final token = 'sometoken';
final loginError = 'someerrormessage';
blocTest('emits [LoginLoading] when successful',
build: () {
when(() => mockUserRepository.authenticate(username: username, password: password)).thenAnswer((_) async => token);
return LoginBloc(userRepository: mockUserRepository, authenticationBloc: mockAuthenticationBloc);
},
act: (bloc) => bloc.add(LoginButtonPressed(username: username, password: password)),
expect: () => [
LoginInitial(),
LoginLoading(),
],
);
});
}
And the error is:
Bad state: A test tried to use any
or captureAny
on a parameter of type AuthenticationState
, but
registerFallbackValue was not previously called to register a fallback value for AuthenticationState
.
To fix, do:
void main() {
setUpAll(() {
registerFallbackValue(/* create a dummy instance of `AuthenticationState` */);
});
}
This instance of AuthenticationState
will only be passed around, but never be interacted with.
Therefore, if AuthenticationState
is a function, it does not have to return a valid object and
could throw unconditionally.
If you cannot easily create an instance of AuthenticationState
, consider defining a Fake
:
class MyTypeFake extends Fake implements MyType {}
void main() {
setUpAll(() {
registerFallbackValue(MyTypeFake());
});
}
Fallbacks are required because mocktail has to know of a valid AuthenticationState
to prevent
TypeErrors from being thrown in Dart's sound null safe mode, while still
providing a convenient syntax.
Describe the bug I'm migrating one personal project to the latest versions and null safety. But I'm having problems doing widget testing on the latest version with mocktail and cubit.
Test I'm trying to run
Error I'm getting
I already tried doing what the error message says, but I'm still getting the same error.