Bloc: How to test exceptions for cubit async methods

Created on 12 Aug 2020  路  3Comments  路  Source: felangel/bloc

Describe the bug
I can't use blocTestmethods for testing exceptions using cubit with Future methods.

To Reproduce
Steps to reproduce the behavior:

  1. Download and setup repo from https://github.com/JanuszHain/bloc_test_cubit_exception
  2. Run tests: 'index 3 or more should throw exception, unit test working incorrectly'
  3. See error in unit test console (unit test fails)

Expected behavior
The test passes, because expected error have been thrown.

Additional context
I have checked why blocTestdoesn't work with Future methods. It is because it expects CubitUnhandledErrorException, otherwise unit test will throw error, making the test fail.
I have created second unit test to show that it is indeed the reason - I simply throw exception wrapped in CubitUnhandledErrorExceptionand it works correctly in case of using Future.error.

See: https://github.com/JanuszHain/bloc_test_cubit_exception/blob/master/lib/test_cubit.dart

I have some questions regarding testing.

  1. Why doesn't my second unit test end if I throw exception instead of using Future.error? I have tried to debug it, but haven't noticed anything that could lead to unit test not being able to end.
  2. Is there a reason why CubitUnhandledErrorExceptionis needed in blocTest? Legacy cubit library didn't have such thing and I think it could be possible to use blocTestwithout wrapping exceptions. (https://github.com/felangel/cubit/blob/master/packages/cubit_test/lib/src/cubit_test.dart)
  3. I have heard that we shouldn't throw exceptions in bloc / cubit. While excepted errors should be handled, I don't think catching every exception is a good practice. If error that shouldn't happen is thrown, shouldn't application crash (therefore we shouldn't catch and handle exceptions that we don't expect to happen)?
  4. How should I implement tests if I want to use cubit instead of bloc streams?
  5. If we consider creating error states for errors that we expect and crashing when error that we don't catch (because we don't want to catch every error that we don't expect to happen) is there any valid case for writing tests for exceptions? If we expect error, we have to handle it and let the user know something happened and unit tests for error state would be easier to write.

Update: In our team we have decided to catch expected errors and make states for it (we have to handle them), if we don't know about exceptions, it should crash (as it is development failure). So we don't have to test exceptions from cubit at all, instead we have to test if correct error state was emitted. I am not closing the issue, because the problem above persists.

bug bloc_test

All 3 comments

Hi @JanuszHain 馃憢
Thanks for opening an issue!

1613 will address points 1 and 2.

  1. If an uncaught error occurs in a cubit it will bubble up to the next zone so if it's not handled upstream it will be surfaced
  2. You can assert that errors are thrown like so:
final exception = Exception('oops');

blocTest<ExceptionCubit, int>(
  'captures uncaught exceptions',
  build: () => ExceptionCubit(),
  act: (cubit) => cubit.throwException(exception),
  errors: <Matcher>[equals(exception)],
);

blocTest<ExceptionCubit, int>(
  'captures calls to addError',
  build: () => ExceptionCubit(),
  act: (cubit) => cubit.addError(exception),
  errors: <Matcher>[equals(exception)],
);

where ExceptionCubit is:

import 'package:bloc/bloc.dart';

class ExceptionCubit extends Cubit<int> {
  ExceptionCubit() : super(0);

  void throwException(Exception e) => throw e;
}
  1. The case for testing exceptions is if you intentionally want to let known exceptions bubble up for some reason to be handled in a different zone for centralized error handling.

Let me know if that helps and thanks again for reporting this 馃憤

Hello,

Thank you, I have checked the changes and works nicely :)
And thank you for explanation of exception testing.

Greetings,
Janusz

Hi @felangel ,

I have checked different unit test and it doesn't end test too if the error is thrown in expect, you can see this on branch that I created to show the bug (splash_cubit_test):

https://github.com/JanuszHain/bloc_test_cubit_exception/tree/exception_in_expect_not_ending_test

It looks like try catch inside blocTest should cover more code, because exception thrown in actworks ok after library update, and in expect not. I am not sure about other functions, but it seems like build and verify can throw exceptions too, which will not end the test with failure.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

shawnchan2014 picture shawnchan2014  路  3Comments

ricktotec picture ricktotec  路  3Comments

abinvp picture abinvp  路  3Comments

1AlexFix1 picture 1AlexFix1  路  3Comments

nhwilly picture nhwilly  路  3Comments