如何使用blocTest对Flutter的CartItemBloc进行单元测试?
前置准备
首先确保你的CartItem模型类继承了Equatable,否则bloc测试无法正确比对两个CartItem实例是否相等,会导致预期状态匹配失败,示例CartItem定义参考:
import 'package:equatable/equatable.dart'; class CartItem extends Equatable { final String itemId; final double price; final int qty; const CartItem({ required this.itemId, required this.price, this.qty = 1, }); CartItem copyWith({ String? itemId, double? price, int? qty, }) { return CartItem( itemId: itemId ?? this.itemId, price: price ?? this.price, qty: qty ?? this.qty, ); } @override List<Object?> get props => [itemId, price, qty]; }
完整测试代码实现
import 'package:bloc_test/bloc_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:pikpo_screen/blocs/cart_item_bloc.dart'; import 'package:pikpo_screen/model/cart_item.dart'; void main() { // 预先定义模拟测试数据 const mockItem1 = CartItem(itemId: "1", price: 35, qty: 1); const mockItem2 = CartItem(itemId: "2", price: 50, qty: 1); group('CartItemBloc 测试', () { late CartItemBloc cartItemBloc; late List<CartItem> initialItems; setUp(() { initialItems = []; cartItemBloc = CartItemBloc(initialItems); }); tearDown(() { cartItemBloc.close(); }); test('初始状态为空列表', () { expect(cartItemBloc.state, equals([])); }); blocTest<CartItemBloc, List<CartItem>>( '触发CartItemCheck事件时正确添加商品到列表', build: () => cartItemBloc, act: (bloc) => bloc.add(CartItemCheck(item: mockItem1)), expect: () => [ [mockItem1] ], ); blocTest<CartItemBloc, List<CartItem>>( '触发CartItemUncheck事件时正确移除对应商品', build: () => cartItemBloc, act: (bloc) async { // 先添加商品再移除 bloc.add(const CartItemCheck(item: mockItem1)); await Future.delayed(const Duration(milliseconds: 10)); bloc.add(const CartItemUncheck(item: mockItem1)); }, expect: () => [ [mockItem1], [], ], ); blocTest<CartItemBloc, List<CartItem>>( '触发increment类型的CartItemUpdate事件时正确增加商品数量', build: () { // 初始状态自带mockItem1 return CartItemBloc([mockItem1]); }, act: (bloc) => bloc.add(const CartItemUpdate(itemId: "1", type: 'increment')), expect: () => [ [mockItem1.copyWith(qty: 2)] ], ); blocTest<CartItemBloc, List<CartItem>>( '触发decrement类型的CartItemUpdate事件时正确减少商品数量', build: () { // 初始状态自带数量为2的mockItem1 return CartItemBloc([mockItem1.copyWith(qty: 2)]); }, act: (bloc) => bloc.add(const CartItemUpdate(itemId: "1", type: 'decrement')), expect: () => [ [mockItem1.copyWith(qty: 1)] ], ); }); }
关键修改说明
blocTest需要明确指定泛型类型Bloc类和状态类型,避免类型匹配错误build参数要直接返回初始化完成的Bloc实例,不要返回可空类型- 所有事件必须传入必填参数,比如
CartItemCheck必须传入要添加的item参数 expect返回的状态序列要和事件触发后的状态变化顺序完全一致,且类型要和Bloc的状态类型(List<CartItem>)匹配- 测试完成后调用
bloc.close()释放资源,避免内存泄漏
内容的提问来源于stack exchange,提问作者Raka Prasetyo
相关产品推荐
相关产品推荐

