MST

星途 面试题库

面试题:Flutter中如何模拟网络请求以测试依赖网络数据的Widget

在一个Flutter应用中,有一个Widget依赖网络获取的数据来显示列表。请描述如何使用Mockito等工具模拟网络请求,从而对这个Widget进行测试,包括如何设置模拟响应数据以及验证Widget在不同网络响应情况下的UI表现。
15.8万 热度难度
前端开发Flutter

知识考点

AI 面试

面试题答案

一键面试
  1. 引入依赖: 在pubspec.yaml文件中添加mockitoflutter_test依赖:
    dev_dependencies:
      mockito: ^[最新版本号]
      flutter_test:
        sdk: flutter
    
    然后运行flutter pub get
  2. 定义网络请求接口和数据模型: 假设我们有一个网络请求接口和数据模型。例如:
    // 数据模型
    class Item {
      final String name;
      Item(this.name);
    }
    
    // 网络请求接口
    abstract class NetworkService {
      Future<List<Item>> fetchItems();
    }
    
  3. 创建Mock对象: 使用mockito生成Mock对象。在项目根目录运行flutter pub run build_runner build,会在test/mocks目录下生成Mock类。假设生成的Mock类为MockNetworkService
    import 'package:mockito/mockito.dart';
    import 'package:your_project/network_service.dart';
    
    class MockNetworkService extends Mock implements NetworkService {}
    
  4. 设置模拟响应数据: 在测试用例中设置模拟响应数据。例如:
    import 'package:flutter/material.dart';
    import 'package:flutter_test/flutter_test.dart';
    import 'package:your_project/item_widget.dart';
    import 'package:your_project/network_service.dart';
    import 'package:mockito/mockito.dart';
    
    void main() {
      group('ItemWidgetTest', () {
        late MockNetworkService mockNetworkService;
    
        setUp(() {
          mockNetworkService = MockNetworkService();
        });
    
        testWidgets('Displays items when network request is successful', (WidgetTester tester) async {
          final List<Item> mockItems = [Item('Item 1'), Item('Item 2')];
          when(mockNetworkService.fetchItems()).thenAnswer((_) async => mockItems);
    
          await tester.pumpWidget(MaterialApp(
            home: ItemWidget(networkService: mockNetworkService),
          ));
          await tester.pumpAndSettle();
    
          expect(find.text('Item 1'), findsOneWidget);
          expect(find.text('Item 2'), findsOneWidget);
        });
      });
    }
    
  5. 验证不同网络响应情况下的UI表现
    • 成功响应:如上述代码,验证列表项是否正确显示。
    • 失败响应:模拟网络请求失败,验证UI是否显示相应的错误提示。例如:
    testWidgets('Displays error when network request fails', (WidgetTester tester) async {
      when(mockNetworkService.fetchItems()).thenThrow(Exception('Network error'));
    
      await tester.pumpWidget(MaterialApp(
        home: ItemWidget(networkService: mockNetworkService),
      ));
      await tester.pumpAndSettle();
    
      expect(find.text('Network error'), findsOneWidget);
    });
    

ItemWidget中,需要在initStatedidChangeDependencies中调用networkService.fetchItems(),并根据结果更新UI。例如:

class ItemWidget extends StatefulWidget {
  final NetworkService networkService;
  ItemWidget({required this.networkService});

  @override
  _ItemWidgetState createState() => _ItemWidgetState();
}

class _ItemWidgetState extends State<ItemWidget> {
  List<Item>? items;
  String? error;

  @override
  void initState() {
    super.initState();
    _fetchItems();
  }

  Future<void> _fetchItems() async {
    try {
      final fetchedItems = await widget.networkService.fetchItems();
      setState(() {
        items = fetchedItems;
      });
    } catch (e) {
      setState(() {
        error = e.toString();
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    if (error!= null) {
      return Center(child: Text(error!));
    }
    if (items == null) {
      return Center(child: CircularProgressIndicator());
    }
    return ListView.builder(
      itemCount: items!.length,
      itemBuilder: (context, index) {
        return ListTile(title: Text(items![index].name));
      },
    );
  }
}