首页 > 解决方案 > 在 mapEventToState 中使用 yield 和 Either 时测试我的块失败

问题描述

我正在学习有关清洁架构的课程,但遇到以下错误。

以下测试失败。

test('should emit [Error] when the input is invalid', () async {
  final tNumberString = '1';
  when(mockInputConverter.stringToUnsignedInteger(any))
    .thenReturn(Left(InvalidInputFailure()));

  final expected = [
    Empty(),
    Error(message: invalidInput),
   ];
   expectLater(bloc.state, emitsInOrder(expected));

   bloc.add(GetTriviaForConcreteNumberEvent(tNumberString));
});

我的 NumberTriviaBloc 如下

part 'number_trivia_event.dart';
part 'number_trivia_state.dart';

const String serverFailureMessage = 'Server Failure';
const String cacheFailureMessage = 'Cache Failure';
const String invalidInput =
    'Invalid input - the number should be a positive integer';

class NumberTriviaBloc extends Bloc<NumberTriviaEvent, NumberTriviaState> {
  NumberTriviaBloc(
      {@required GetConcreteNumberTrivia concrete,
      @required GetRandomNumberTrivia random,
      @required this.inputConverter})
      : assert(concrete != null),
        assert(random != null),
        assert(inputConverter != null),
        _getConcreteNumberTrivia = concrete,
        _getRandomNumberTrivia = random,
        super(Empty());

  final GetConcreteNumberTrivia _getConcreteNumberTrivia;
  final GetRandomNumberTrivia _getRandomNumberTrivia;
  final InputConverter inputConverter;

  @override
  Stream<NumberTriviaState> mapEventToState(
    NumberTriviaEvent event,
  ) async* {
    if (event is GetTriviaForConcreteNumberEvent) {
      final inputEither =
          inputConverter.stringToUnsignedInteger(event.numberString);

      yield* inputEither.fold(
        (l) async* {
          yield Error(message: invalidInput);
        },
        (r) => throw UnimplementedError(),
      );
    }
  }
}

我不太熟悉 bloc 模式以及流和状态的测试机制。我以某种方式猜测代码没有正确执行,因为失败消息如下

ERROR: Expected: should do the following in order:
emit an event that Empty:<Empty>
emit an event that Error:<Error>
Actual: Empty:<Empty>
Which: was not a Stream or a StreamQueue

标签: fluttertestingdartyieldbloc

解决方案


所以我自己解决了。问题中的代码对旧版本的 dart 有效。现在

bloc.state

会破坏代码。反而

bloc

应该用来获取状态。

第二个问题是不再可能拥有

throw UnimplementedError();

在 Either 对象的 fold 方法中。这将导致在任何一种情况下都抛出异常。fold 调用的正确函数中必须有一些非异常逻辑。

修改反映在下面的代码中。

number_trivia_bloc_test.dart

test('should emit [Error] when the input is invalid', () async {
  when(mockInputConverter.stringToUnsignedInteger(any))
      .thenReturn(Left(InvalidInputFailure()));

  bloc.add(GetTriviaForConcreteNumberEvent(tNumberString));

  final expected = [
    Error(message: invalidInput),
  ];
  expectLater(bloc, emitsInOrder(expected));
});

number_trivia_bloc.dart

@override
Stream<NumberTriviaState> mapEventToState(NumberTriviaEvent event,
  ) async* {
  if (event is GetTriviaForConcreteNumberEvent) {
    final inputEither =
      inputConverter.stringToUnsignedInteger(event.numberString);

    yield* inputEither.fold(
      (failure) async* {
        yield Error(message: invalidInput);
      },
      (integer) async* {
        yield null;
      },
    ); 
  }
}

推荐阅读