Flutter 中提供者的单元测试

Posted

技术标签:

【中文标题】Flutter 中提供者的单元测试【英文标题】:Unit Testing for Providers in Flutter 【发布时间】:2020-05-01 06:08:10 【问题描述】:

我们已经在 TDD 方法中启动了一个关于 Flutter 的新项目。我正在使用提供者进行状态管理。 在尝试编写小部件测试时,我们面临着测试提供者的问题。 您能否举个例子来建议为提供者编写单元测试和小部件注入提供者。

我遇到以下问题

══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════
The following ProviderNotFoundException was thrown running a test:
Error: Could not find the correct Provider above this SplashScreen Widget

To fix, please:

Ensure the Provider is an ancestor to this SplashScreen Widget
Provide types to Provider
Provide types to Consumer
Provide types to Provider.of()
Always use package imports. Ex: `import 'package:my_app/my_code.dart';
Ensure the correct context is being used.

══╡启动画面代码╞═══════════════════════════════════╕>

import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../../routes.dart';
import '../../constants/constants.dart';
import '../../providers/provider.dart';
import '../../services/navigation_service.dart';
import '../../utils/utlis.dart';

class SplashScreen extends StatefulWidget 
  @override
  SplashScreenState createState() => SplashScreenState();


class SplashScreenState extends State 
  void startTime() 
    const _duration = Duration(seconds: Preferences.splashScreenTime);
    Timer(_duration, _getInitialData);
    _getInitialData();
  

  dynamic _getInitialData() async 
    final TokenProvider tokenProvider =
    Provider.of(context, listen: false);

    await tokenProvider.setAccessToken();

    navigationPage();
  

  void navigationPage() 
    NavigationService.pushReplacementNamedTo(Routes.home_screen);
  

  @override
  void initState() 
    super.initState();
    startTime();
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      backgroundColor: Colors.white,
      body: Stack(
        key: const Key('splashScreen_body'),
        fit: StackFit.expand,
        children: [
          Image.asset(
            'assets/images/flutter.png',
            key: const Key('splashScreen_image'),
          )
        ],
      ),
    );
  

提前致谢

【问题讨论】:

【参考方案1】:

您需要将要测试的小部件包装在该小部件使用的提供程序中。

因此,您可能想写:

await tester.pumpWidget(
  Provider<TokenProvider>(
    child: SplashScreen(),
  ),
);

【讨论】:

谢谢 Remi,如果我使用多个提供商,我们需要什么? 同样的,只是添加更多的提供者 你知道如何用'stacked'来做吗?它是 Provider 的包装器。【参考方案2】:

如果您对此类代码进行了重复测试, 你可以使用extension

import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
import 'package:mockito/mockito.dart';

  Widget wrapWithMaterial() => MaterialApp(
    home: Provider<TokenProvider>(
      create: (_) => MockTokenProvider(),
      child: Scaffold(
        body: this,
      ),
    ),
  );

 class MockTokenProvider extends Mock implements TokenProvider 

现在在你的测试中你可以做

await tester.pumpWidget(
  SplashScreen().wrapWithMaterial()
);

【讨论】:

以上是关于Flutter 中提供者的单元测试的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 测试的最新进展

Flutter 单元测试例子

VS Code 无法识别 Flutter 中的单元测试

Flutter Firebase 函数的单元测试

Flutter:单元测试一个 Cubit 问题

Flutter 测试失败,单元测试预期和实际状态对象相同但仍然失败