Flutter业务逻辑管理插件bloc_presentation_test的使用
Flutter业务逻辑管理插件bloc_presentation_test的使用
bloc_presentation_test
是一个用于简化 BlocPresentationMixin
ed Bloc
/Cubit
测试的包。它与 bloc_presentation
包一起使用,以提供更直观的测试体验。
安装
首先,在项目的 pubspec.yaml
文件中添加 bloc_presentation_test
依赖项:
flutter pub add --dev bloc_presentation_test
使用方法
bloc_presentation_test
提供了两种方式来模拟 presentation
流:
- 使用
whenListenPresentation
函数 - 扩展目标
BlocPresentationMixin
edBloc
/Cubit
为MockPresentationBloc
/MockPresentationCubit
方法1 - whenListenPresentation
创建 Mock 类
首先,创建你的 BlocPresentationMixin
ed Bloc
/Cubit
的 mock 类。可以使用 bloc_test
包来实现这一点。
class MockCommentCubit extends MockCubit implements CommentCubit {}
获取 StreamController
然后,创建 MockCommentCubit
的实例,并通过调用 whenListenPresentation
来获取 StreamController
。
final mockCubit = MockCommentCubit();
final controller = whenListenPresentation(mockCubit);
这将模拟 MockCommentCubit
的 presentation
流,你可以订阅这个流。获取到的控制器可以用来向 presentation
流添加事件。
controller.add(const FailedToUpvote());
如果你指定了 initialEvents
参数,presentation
流将被模拟成给定事件的流。
final controller = whenListenPresentation(
mockCubit,
const [FailedToUpvote(), SuccessfulUpvote()],
);
返回的 StreamController
在 Cubit
/Bloc
的 close
方法中被释放。如果你重写了这个方法,则需要手动释放控制器。
方法2 - MockPresentationCubit
/MockPresentationBloc
创建 Mock 类
首先,使用 MockPresentationBloc
/MockPresentationCubit
创建你的 BlocPresentationMixin
ed Bloc
/Cubit
的 mock 类。
class MockCommentCubit extends MockPresentationCubit<CommentState> implements CommentCubit {}
发送模拟事件
然后,创建 MockCommentCubit
的实例并调用 emitMockPresentation
。
final mockCubit = MockCommentCubit();
mockCubit.emitMockPresentation(const FailedToUpvote());
这将向 presentation
流添加 FailedToUpvoteEvent
事件。
最后,记得调用 MockCommentCubit
的 close
方法。
示例代码
下面是一个完整的示例,展示了如何使用 bloc_presentation_test
进行测试。
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:bloc_presentation/bloc_presentation.dart';
import 'package:bloc_presentation_test/bloc_presentation_test.dart';
import 'package:bloc_test/bloc_test.dart';
import 'package:test/test.dart';
// 定义 CounterCubit
class CounterCubit extends Cubit<int> with BlocPresentationMixin<int, CounterCubitEvent> {
CounterCubit() : super(0);
void count() {
final newNumber = state + 1;
if (state < 10) {
emitPresentation(CounterPresentationEvent(newNumber));
}
emit(newNumber);
}
}
// 定义 CounterCubitEvent
sealed class CounterCubitEvent {}
final class CounterPresentationEvent implements CounterCubitEvent {
const CounterPresentationEvent(this.number);
final int number;
@override
int get hashCode => number.hashCode;
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is CounterPresentationEvent && other.number == number;
}
}
// 定义 MockCounterPresentationCubit
class MockCounterPresentationCubit extends MockPresentationCubit<int, CounterCubitEvent> implements CounterCubit {}
// 定义 MockCounterCubit
class MockCounterCubit extends MockCubit<int> implements CounterCubit {}
void main() {
mainMockPresentationCubit();
mainWhenListenPresentation();
mainBlocPresentationTest();
}
void mainMockPresentationCubit() {
late MockCounterPresentationCubit mockCubit;
setUp(() {
mockCubit = MockCounterPresentationCubit();
});
tearDown(() {
mockCubit.close();
});
test('presentation stream emits events properly', () async {
mockCubit.emitMockPresentation(const CounterPresentationEvent(5));
await expectLater(
mockCubit.presentation,
emitsInOrder([
equals(const CounterPresentationEvent(5)),
]),
);
});
}
void mainWhenListenPresentation() {
late MockCounterCubit mockCubit;
late StreamController<CounterCubitEvent> controller;
setUp(() {
mockCubit = MockCounterCubit();
controller = whenListenPresentation(
mockCubit,
initialEvents: [const CounterPresentationEvent(1)],
);
});
tearDown(() {
mockCubit.close();
});
test('presentation stream emits events properly', () async {
controller.add(const CounterPresentationEvent(2));
await expectLater(
mockCubit.presentation,
emitsInOrder([
equals(const CounterPresentationEvent(1)),
equals(const CounterPresentationEvent(2)),
]),
);
});
}
void mainBlocPresentationTest() {
CounterCubit buildCubit() => CounterCubit();
blocPresentationTest<CounterCubit, int, CounterCubitEvent>(
'emits correct presentation event after calling count when state was smaller than 10',
build: buildCubit,
act: (cubit) => cubit.count(),
expectPresentation: () => const [
CounterPresentationEvent(1),
],
);
blocPresentationTest<CounterCubit, int, CounterCubitEvent>(
'does not emit presentation event if count has not been called',
build: buildCubit,
expectPresentation: () => const <CounterPresentationEvent>[],
);
blocPresentationTest<CounterCubit, int, CounterCubitEvent>(
'emits correct presentation event after calling count 2 times when state was smaller than 10',
build: buildCubit,
act: (cubit) => cubit..count()..count(),
skipPresentation: 1,
expectPresentation: () => const [
CounterPresentationEvent(2),
],
);
blocPresentationTest<CounterCubit, int, CounterCubitEvent>(
'does not emit presentation event after calling count when state was 10',
build: buildCubit,
seed: () => 10,
act: (cubit) => cubit.count(),
expectPresentation: () => const <CounterPresentationEvent>[],
);
}
这个示例展示了如何使用 bloc_presentation_test
来测试带有 BlocPresentationMixin
的 Cubit
。你可以根据需要调整和扩展这些测试用例,以适应你自己的业务逻辑。
更多关于Flutter业务逻辑管理插件bloc_presentation_test的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter业务逻辑管理插件bloc_presentation_test的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,关于Flutter业务逻辑管理插件bloc_presentation_test
的使用,虽然这个特定的包名听起来像是用于测试Bloc模式的某种工具或框架的特定实现,但需要注意的是,在Flutter社区中,更常见的与Bloc模式相关的包是flutter_bloc
,它用于状态管理和业务逻辑处理。flutter_bloc
通常与bloc_test
包一起使用来进行Bloc相关的测试。
不过,为了回应你的帖子,我将假设你提到的bloc_presentation_test
是一个用于辅助测试Bloc逻辑的工具,并且你想要了解如何在Flutter项目中使用它来管理业务逻辑并进行测试。由于这个包的具体实现细节可能并不广为人知,我将提供一个基于flutter_bloc
和bloc_test
的示例,这通常是处理Flutter中Bloc逻辑和测试的标准方式。
1. 设置Flutter项目
首先,确保你的Flutter项目已经创建,并且在pubspec.yaml
文件中添加了flutter_bloc
和bloc_test
依赖:
dependencies:
flutter:
sdk: flutter
flutter_bloc: ^8.0.0 # 请检查最新版本
dev_dependencies:
bloc_test: ^8.0.0 # 请检查最新版本
test: any
运行flutter pub get
来安装这些依赖。
2. 创建Bloc和事件/状态
定义一个简单的事件和状态类,以及一个处理这些事件的Bloc。
// events.dart
import 'package:equatable/equatable.dart';
abstract class CounterEvent extends Equatable {
const CounterEvent();
@override
List<Object> get props => [];
}
class IncrementEvent extends CounterEvent {}
class DecrementEvent extends CounterEvent {}
// states.dart
import 'package:equatable/equatable.dart';
abstract class CounterState extends Equatable {
const CounterState();
@override
List<Object> get props => [];
}
class CounterInitial extends CounterState {}
class CounterStateWithCount extends CounterState {
final int count;
const CounterStateWithCount({required this.count});
@override
List<Object> get props => [count];
}
// counter_bloc.dart
import 'package:bloc/bloc.dart';
import 'events.dart';
import 'states.dart';
class CounterBloc extends Bloc<CounterEvent, CounterState> {
CounterBloc() : super(CounterInitial());
@override
Stream<CounterState> mapEventToState(CounterEvent event) async* {
if (event is IncrementEvent) {
yield* _handleIncrementEvent();
} else if (event is DecrementEvent) {
yield* _handleDecrementEvent();
}
}
Stream<CounterState> _handleIncrementEvent() async* {
final currentState = state;
if (currentState is CounterStateWithCount) {
yield CounterStateWithCount(count: currentState.count + 1);
}
}
Stream<CounterState> _handleDecrementEvent() async* {
final currentState = state;
if (currentState is CounterStateWithCount) {
yield CounterStateWithCount(count: currentState.count - 1);
}
}
}
3. 使用BlocProvider在Flutter UI中提供Bloc
// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'counter_bloc.dart';
import 'counter_page.dart';
void main() {
runApp(BlocProvider(
create: (_) => CounterBloc(),
child: MyApp(),
));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: CounterPage(),
);
}
}
4. 创建UI组件并消费Bloc
// counter_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'counter_bloc.dart';
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Counter')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
BlocBuilder<CounterBloc, CounterState>(
builder: (context, state) {
if (state is CounterStateWithCount) {
return Text(
'You have pushed the button this many times:',
style: Theme.of(context).textTheme.headline4,
);
} else if (state is CounterInitial) {
return Text('0');
} else {
return Text('?');
}
},
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () => context.read<CounterBloc>().add(IncrementEvent()),
child: Text('Increment'),
),
SizedBox(height: 10),
ElevatedButton(
onPressed: () => context.read<CounterBloc>().add(DecrementEvent()),
child: Text('Decrement'),
),
],
),
),
);
}
}
5. 使用bloc_test进行单元测试
// counter_bloc_test.dart
import 'package:bloc_test/bloc_test.dart';
import 'package:test/test.dart';
import 'counter_bloc.dart';
void main() {
group('CounterBloc', () {
blocTest<CounterBloc, CounterState>(
'emits [CounterStateWithCount(1)] when IncrementEvent is added',
build: () => CounterBloc(),
act: (bloc) => bloc.add(IncrementEvent()),
expect: [CounterStateWithCount(count: 1)],
);
blocTest<CounterBloc, CounterState>(
'emits [CounterStateWithCount(0), CounterStateWithCount(-1)] when DecrementEvent is added',
build: () => CounterBloc()..add(IncrementEvent()),
act: (bloc) => bloc.add(DecrementEvent()),
expect: [
CounterStateWithCount(count: 1),
CounterStateWithCount(count: 0),
CounterStateWithCount(count: -1),
],
skip: 1, // Skip the initial state
);
});
}
这个示例展示了如何使用flutter_bloc
进行状态管理,并使用bloc_test
进行单元测试。如果你提到的bloc_presentation_test
是一个特定的、不同的包,请提供更多信息以便给出更准确的示例。在大多数情况下,flutter_bloc
和bloc_test
是处理Flutter中Bloc逻辑和测试的标准方式。