bloc unit testing - thenThrow functionality

Created on 10 Jun 2020  路  5Comments  路  Source: felangel/bloc

Hi,
I'm testing my bloc using bloc_test and mockito.
For some reason when trying to test the "Failure" state in my bloc, i get weird error:

```
Expected: [
UserAccountTransactionsLoading:UserAccountTransactionsLoading,
UserAccountTransactionsError:UserAccountTransactionsError
]
Actual: [
UserAccountTransactionsLoading:UserAccountTransactionsLoading,
UserAccountTransactionsError:UserAccountTransactionsError
]
Which: was UserAccountTransactionsError: instead of UserAccountTransactionsError: at location [1]

package:test_api expect
package:bloc_test/src/bloc_test.dart 143:29 blocTest..
===== asynchronous gap ===========================
dart:async _asyncThenWrapperHelper
package:bloc_test/src/bloc_test.dart blocTest..
dart:async runZoned
package:bloc_test/src/bloc_test.dart 135:11 blocTest.



My test:

blocTest(
'emits [loading, error] when FetchUserAccountTransactions is added and loadAccountTransactions fails',
build: () async {
when(accountRepository.loadAccountTransactions('10001', 'dolor')).thenThrow(Exception("oops"));
return userAccountTransactionsBloc;
},
act: (bloc) => bloc.add(FetchUserAccountTransactions('10001', 'dolor')),
expect: [
UserAccountTransactionsLoading(),
UserAccountTransactionsError(
exception: Exception("oops"),
),
]
);


And my bloc:

@override
Stream mapEventToState(UserAccountTransactionsEvent event) async* {
try {
if (event is FetchUserAccountTransactions) {
yield UserAccountTransactionsLoading();
List accountTransactions = await accountRepository.loadAccountTransactions(event.customerId, event.accountId);
yield UserAccountTransactionsLoaded(
transactions: accountTransactions
);
} else {
log.severe('Unsupported Event');
yield UserAccountTransactionsError(
exception: Exception('Unsupported Event')
);
}
} catch(e) {
log.severe(e);
yield UserAccountTransactionsError(
exception: e,
);
}
}
```

So the error states that it expected UserAccountTransactionsError and the actual was UserAccountTransactionsError - which is the same, so I'm not sure what's wrong with the error handling

bloc_test question

Most helpful comment

@kndl22 thanks for the additional information. I believe the problem is Exception does not override == and hashCode so you can't compare exceptions by value.

Can you try refactoring your UserAccountTransactionError to look like:

class UserAccountTransactionsError extends UserAccountTransactionsState {

  UserAccountTransactionsError({@required this.exception});

  final Exception exception;

  @override
  List<Object> get props => [exception?.message];
}

All 5 comments

Hi @kndl22 馃憢
Thanks for opening an issue!

I鈥檓 guessing your state is not extending Equatable, properties within the state are not extending equatable, or the props override on your Equatable classes doesn鈥檛 contain all of the class properties.

Let me know if that helps and if not can you please share your bloc state implementation? Thanks 馃憤

Hi @felangel ,
Thanks for being responsive!

This is how my "base state" implemented:

class UserAccountTransactionsState extends Equatable {

  @override
  List<Object> get props => [];
}

And this is my "error" state:

class UserAccountTransactionsError extends UserAccountTransactionsState {

  UserAccountTransactionsError({@required this.exception});

  final Exception exception;

  @override
  List<Object> get props => [exception];
}

@kndl22 thanks for the additional information. I believe the problem is Exception does not override == and hashCode so you can't compare exceptions by value.

Can you try refactoring your UserAccountTransactionError to look like:

class UserAccountTransactionsError extends UserAccountTransactionsState {

  UserAccountTransactionsError({@required this.exception});

  final Exception exception;

  @override
  List<Object> get props => [exception?.message];
}

Thanks @felangel !
That's right - changing my equatable state to handle diff with exception.toString() did the trick.

class UserAccountTransactionsError extends UserAccountTransactionsState {

  UserAccountTransactionsError({@required this.exception});

  final Exception exception;

  @override
  List<Object> get props => [exception.toString()];
}

1 thing i should mention is that the official docs for the Exception class shows that in-fact it does override hashCode and == operator. Also, the message property doesn't exist for some reason. So I'm still bit confused why it didn't work before.

Anyway, thanks again for your hard work! Much appreciation!

I don鈥檛 think it overrides == and hashCode. The docs show that the method/property exist on the object but by default equality is referential.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mikededo picture mikededo  路  28Comments

felangel picture felangel  路  32Comments

pczn0327 picture pczn0327  路  67Comments

fvisticot picture fvisticot  路  31Comments

felangel picture felangel  路  29Comments