Describe the bug
I've been looking on how to test the bloc listener here and here but for some reason the following test won't complete and I'm not sure why is that.
To Reproduce
This is the test in question:
Test that is not completing
And this is the bloc code for the login. I can see the breakpoints hitting but when the state LoginFailure returns it just won't complete.
Expected behavior
Test to be completed
Screenshots
It can even run for minutes! if I don't stop it manually
*Logs *
$ flutter doctor -v
[β] Flutter (Channel stable, v1.9.1+hotfix.4, on Microsoft Windows [Version 10.0.18362.418], locale en-US)
β’ Flutter version 1.9.1+hotfix.4 at C:\flutter\flutter
β’ Framework revision cc949a8e8b (5 weeks ago), 2019-09-27 15:04:59 -0700
β’ Engine revision b863200c37
β’ Dart version 2.5.0
[β] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
β’ Android SDK at C:\Android\android-sdk
β’ Android NDK location not configured (optional; useful for native profiling support)
β’ Platform android-28, build-tools 28.0.3
β’ ANDROID_HOME = C:\Android\android-sdk
β’ Java binary at: C:\Program Files\Java\jdk1.8.0_221\bin\java
β’ Java version Java(TM) SE Runtime Environment (build 1.8.0_221-b11)
β’ All Android licenses accepted.
[!] Android Studio (not installed)
β’ Android Studio not found; download from https://developer.android.com/studio/index.html
(or visit https://flutter.dev/setup/#android-setup for detailed instructions).
[β] VS Code (version 1.39.2)
β’ VS Code at C:\Users\mihai\AppData\Local\Programs\Microsoft VS Code
β’ Flutter extension version 3.6.0
[!] Connected device
! No devices available
! Doctor found issues in 2 categories.
When removing one of the expected states from the test I get the following error
The following assertion was thrown running a test:
A Timer is still pending even after the widget tree was disposed.
'package:flutter_test/src/binding.dart':
Failed assertion: line 1056 pos 7: '_currentFakeAsync.nonPeriodicTimerCount == 0'
Hi @mihai9112 π
Thanks for opening an issue!
Iβll take a closer look shortly but at first glance your expectLater should come before the βactβ because you can potentially miss states. Also, it seems like youβre writing widget tests to test a bloc which is not recommended. Blocs should be unit tested and when writing widget tests the blocs should be mocked.
Let me know if that helps and Iβll take a closer look at the test shortly π
Thank you for you quick reply. I will act on your recommendations. The reason why I'm widget testing is to check if the SnackBar is showning. The only way to wait for it to show, was to listen if all the states have been emitted successfully. I will try and mock the bloc.
No problem! In that case I would use whenListen to mock the bloc states and then expect that the SnackBar is shown.
Let me know if that helps π
Good news and bad news.
The bloc_test package worked in that test where I was testing if the snack bar will be displayed.
Now most of my tests that unit test a specific bloc and not a mocked bloc fail with the following message:
Expected: should do the following in order:
* emit an event that Uninitialized:<Uninitialized>
* emit an event that Unauthenticated:<Unauthenticated>
Actual: Uninitialized:<Uninitialized>
Which: was not a Stream or a StreamQueue
Is the package bloc_test something that must be used always in the future, even when testing an actual instance of a bloc and not a mocked one?
Nice! Can you share the bloc unit tests that are failing?
These tests used to pass before: https://github.com/mihai9112/reazzon/blob/feature/testing/test/authentication_tests/authentication_bloc_test.dart
Now they are failing with that above mentioned error
@mihai9112 you should change your expectation to
expectLater(_authenticationBloc, emitsInOrder(expectedStates));
because in v1.0.0 blocs extend Stream
so there is no longer a state stream property. The state property now refers to the bloc's current state.
Let me know if that helps π
That worked, thank you!
One thing that also caught my eye with the new package is that if you want to mock the return of the current state, you now have to initialise the stream first and then mock the return.
Before
when(_authenticationBlocMock.state).thenAnswer((_) => Unauthenticated());
After
whenListen(_authenticationBlocMock, Stream<AuthenticationState>.empty());
when(_authenticationBlocMock.state).thenReturn(Unauthenticated());
It's not a major issue, but it can be unintuitive for beginners in the bloc package. Maybe have extra method in the bloc test that will do that automatically?
Keep up the good work anyway!
@mihai9112 I'm glad I was able to help! Yeah I'm working on improving the testing as we speak π
Thanks so much! π
Most helpful comment
@mihai9112 you should change your expectation to
because in v1.0.0 blocs extend
Stream
so there is no longer a state stream property. The state property now refers to the bloc's current state.Let me know if that helps π