Hi,
I am trying to do widgetTest while stubbing the bloc as described in the documentation here.
My widget using the Bloc with BlocBuilder but it doesn't seems to listen to the Bloc stream in testing
So when I use whenListen(mockBloc, Stream.fromIterable([BlocState()])) it wont emit any states to the builder and the BlocBuilder wont rebuild.
And also, in the BlocBuilder (builder: (context, state) {
print('${state.toString()}'); // This will print null during testing (and works great in the app)
} )
How does mocking the bloc helps when doing widget test?
Can you help?
Hi @MotiBartov 👋
Thanks for opening an issue!
If you want to just stub the state of the bloc which will be used by BlocBuilder you should rely on when rather than whenListen:
when(mockBloc.state).thenReturn(BlocState());
Rely on whenListen when you want to test functionality executed within BlocListener.
Hope that helps 👍
Thank you very much for such quick reasonse!
Maybe you can add this to the documentation?
Also, how can I map event to state with the stubbed bloc?
Something like this maybe?:
when(bloc.event).thenAnswer(BlocState())
Best regards,
Moti.
בתאריך יום ד׳, 24 ביוני 2020, 19:35, מאת Felix Angelov <
[email protected]>:
Closed #1338 https://github.com/felangel/bloc/issues/1338.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/felangel/bloc/issues/1338#event-3478348087, or
unsubscribe
https://github.com/notifications/unsubscribe-auth/AGVTAIFUHNKQU2XK7YQC5GDRYITOHANCNFSM4OGYSOGA
.
No problem! Yeah I'll try to update the docs to make this more clear.
Regarding your second question, you shouldn't need to mock mapEventToState. If you're mocking the bloc, then you should be testing the widget that uses the bloc and can verify that events are added when interacting with the UI via verify:
verify(bloc.add(SomeEvent())).called(1);
Hope that helps 👍
Hi, Thanks again!
Yes, it make sense to use verify as you explained.
But here is the thing, when I do widget test, a typical flow goes like this:
So when working with stub bloc how it can emit different states for a given events in a sequence ?
for example here is my test:
`
await tester.runAsync(() async{
when(mockBloc.state).thenReturn(InitState()); // Init state
await _pumpTestWidget(tester);
await tester.pump();
await tester.pump();
final textInput = find.byKey(Key("TextInput"));
expect(textInput, findsNWidgets(1));
await tester.tap(textInput);
verify(mockBloc.add(TextInputClicked())).called(1); //This will pass
when(mockBloc.state).thenReturn(TextInputState(text: "Text from new state" )); // This doesn't seems to work
await tester.pumpAndSettle();
final someText = find.text("Text from new state");
expect(someText, findsNWidgets(1)); //This will fail
});`
Thanks,
Moti.
Hi, Thanks again.
I have another question,
When using when(mockBloc.state).thenReturn(BlocState()); as you explained, i noticed that BlocListener and BlocBuilder.condition are not called. Is this a normal behaviour?
Thanks,
Moti.
Yeah that’s expected because when you stub the state you aren’t stubbing the stream and the stream is what the blocs are subscribing to and invoking the condition in response to 👍
Hi and thanks for your attention on this,
Well, so how would you recommend to test these functionalities with stubbed bloc?
You see, when doing WidgetTest some of behaviours related to states that coming from the BlocListener or the condition.
I am using the Listener to show dialogs and bottom sheets for example (is this good practice?).
When the stubbed bloc 'emits' ShowDialog state, it should be catched by the listener that shows the dialog, so how can this be tested?
Something like this:
`
when(mockBloc.state).thenReturn(ShowDlalog());
tester.pumpAndSettle();
expect(find.byType(Dialog), findsOnWidget) // This will fail as it taken cared by the listener and filtered by the condition
`
Right now, I am using the bloc_test for unit testing which works very nice, but when it comes to WidgetTest I still use the real bloc as i am felling that stubbed bloc doesn't seems to be ready enough or I am just not using it properly.
I've followed the documentation and looked the sample app but it doesn't covers use cases like BlocListener and conditioned.
Thanks and Regards,
Moti.
@moti0375 I would highly recommend using a mock bloc for your widget tests. Can you please provide a link to a sample app which illustrates the problems you're facing when using a mock bloc and I'm happy to take a look and open a pull request with any suggestions 👍
Hi,
I am sorry for this late response, I haven't neglected this issue.
It seems that after updating to the latest version and following your explanations I think I've figured out how to work with the mockBloc.
When I want to test the BLocListener path I use the whenListen() and when I want to test the builder path i use when(mockBloc.state).thenReturn(BlocState());, as you explained.
I must say the until I've updated to the latest version, the whenListen didn't worked..
However, now I have more confidence both in blocTest and mockBloc.
Thanks!
Most helpful comment
Hi,
I am sorry for this late response, I haven't neglected this issue.
It seems that after updating to the latest version and following your explanations I think I've figured out how to work with the mockBloc.
When I want to test the BLocListener path I use the
whenListen()and when I want to test the builder path i usewhen(mockBloc.state).thenReturn(BlocState());, as you explained.I must say the until I've updated to the latest version, the
whenListendidn't worked..However, now I have more confidence both in blocTest and mockBloc.
Thanks!