繁体   English   中英

Flutter 集成测试用例在运行时失败

[英]Flutter Integration test case fails when run

我正在尝试在我的应用程序中运行集成测试。 该屏幕是我的登录屏幕,它会引导注册流程并登录到主屏幕。 我正在使用框架本身的颤振集成测试。

我尝试在登录屏幕上运行集成测试,但出现此错误,

运行测试时抛出以下 TestFailure 对象:预期:小部件树中正好有一个匹配节点实际:_WidgetPredicateFinder:<零小部件与小部件匹配谓词(闭包:(小部件)=> bool)(忽略舞台外小部件)>其中:意味着没有找到,但预计会有一个

我的登录屏幕看起来像这样

class LoginScreen extends StatefulWidget {
  static String tag = loginScreenRoute;

  const LoginScreen({Key? key}) : super(key: key);

  @override
  State<LoginScreen> createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  final _userLoginFormKey = GlobalKey<FormState>();

  String? _userName = "";
  String? _password = "";
  bool _invisiblePass = false;

  TextEditingController usernameController = TextEditingController();
  TextEditingController passwordController = TextEditingController();

  bool hasInterNetConnection = false;
  late StreamSubscription _connectionChangeStream;

  @override
  initState() {
    //Create instance
    ConnectionUtil connectionStatus = ConnectionUtil.getInstance();
    //Initialize
    connectionStatus.initialize();
    //Listen for connection change
    _connectionChangeStream =
        connectionStatus.connectionChange.listen(connectionChanged);

    super.initState();
  }

  @override
  void dispose() {
    _connectionChangeStream.cancel();
    super.dispose();
  }

  void connectionChanged(dynamic hasConnection) {
    setState(() {
      hasInterNetConnection = hasConnection;
      //print(isOffline);
    });
    if (!hasInterNetConnection) {
      offlineBar(context);
    }
  }

  final loading = Row(
    mainAxisAlignment: MainAxisAlignment.center,
    children: const <Widget>[
      CircularProgressIndicator(
        color: lightWTextColor,
      ),
      Text(" Login in ... Please wait")
    ],
  );

  void _showPassword() {
    setState(() {
      _invisiblePass = !_invisiblePass;
    });
  }

  @override
  Widget build(BuildContext context) {

    //// user email ////
    TextFormField userName() => TextFormField(
          key: const Key('login username input'),
          autofocus: false,
          keyboardType: TextInputType.emailAddress,
          controller: usernameController,
          validator: validateEmail,
          onSaved: (value) => _userName = value!.trim(),
          textInputAction: TextInputAction.next,
          style: AppTheme.body1WTextStyle,
          decoration: buildInputDecoration(
            'Enter Email',
            Icons.email,
            lightWTextColor.withOpacity(0.4),
          ),
          // focusNode: _usernameFocusNode,
          // onFieldSubmitted: (String val) {
          //   final focusNode = FocusNode();
          //   focusNode.unfocus();
          // },
        );

    //// user password ////
    TextFormField userPassword() => TextFormField(
          key: const Key('login password input'),
          obscureText: !_invisiblePass,
          keyboardType: TextInputType.visiblePassword,
          controller: passwordController,
          validator: validatePassword,
          onSaved: (value) => _password = value!.trim(),
          textInputAction: TextInputAction.done,
          style: AppTheme.body1WTextStyle,
          decoration: buildInputDecoration(
            'Enter Password',
            Icons.vpn_lock,
            lightWTextColor.withOpacity(0.4),
          ).copyWith(
            suffixIcon: GestureDetector(
              onTap: () {
                _showPassword();
              },
              child: Icon(
                _invisiblePass ? Icons.visibility : Icons.visibility_off,
                color: Colors.black54,
              ),
            ),
          ),
        );

    final forgotLabel = Padding(
      padding: const EdgeInsets.all(0.0),
      child: Container(
        alignment: Alignment.topRight,
        child: TextButton(
          child: const Text(
            "Forgot password?",
            style: AppTheme.body1WTextStyle,
          ),
          onPressed: () {
            Navigator.of(context).pushNamed(passwordResetScreenRoute);
          },
        ),
      ),
    );

    final signupLabel = Padding(
      padding: const EdgeInsets.all(10.0),
      child: TextButton(
        child: const Text(
          "Sign Up for an Account",
          style: AppTheme.subTitleWTextStyle,
        ),
        onPressed: () {
          Navigator.of(context).pushNamed(
            userEditScreenRoute,
            arguments: eProfile.addProfile,
          );
        },
      ),
    );

    final loginButton = ButtonWidget(
      key: const Key('login button'),
      text: 'LOG IN',
      btnColor: accentColor,
      borderColor: accentColor,
      textColor: lightWTextColor,
      onPressed: () {
        Navigator.of(context).pushReplacementNamed(homeScreenRoute);
        // _submit();
      },
    );

    final loginForm = Form(
      key: _userLoginFormKey,
      autovalidateMode: AutovalidateMode.onUserInteraction,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          userName(),
          const SizedBox(
            height: 10.0,
          ),
          userPassword(),
          forgotLabel,
          const SizedBox(
            height: 10.0,
          ),
          loginButton,
          const SizedBox(
            height: 10.0,
          ),
          signupLabel,
        ],
      ),
    );

    final mainBody = InkWell(
      onTap: () {
        FocusScope.of(context).requestFocus(FocusNode());
      },
      child: Container(
        height: MediaQuery.of(context).size.height,
        width: MediaQuery.of(context).size.width,
        decoration: wBackground(),
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 10.0),
          child: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Image.asset(
                  'assets/images/_logo.png',
                  height: 200.0,
                ),
                Expanded(
                  flex: 1,
                  child: loginForm, //Text('this text here'),
                ),
              ],
            ),
          ),
        ),
      ),
    );

    return SafeArea(
      child: Scaffold(
        body: SingleChildScrollView(
          child: mainBody,
        ),
      ),
    );

  }
}

当我尝试点击登录按钮导航到主屏幕时,测试失败。

我的测试用例是这样的

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();
  //
  // start.main();
  login.main();
}

//
void main() {
  doLoginTest();
}

void doLoginTest() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  testWidgets("Login in test run", (WidgetTester tester) async {
    //
    pawfect.main();
    await tester.pumpAndSettle(const Duration(seconds: 3));
    //test here

    final Finder login =
        find.byWidgetPredicate((widget) => widget is LoginScreen);
    expect(login, findsOneWidget);
    await tester.pumpAndSettle(const Duration(seconds: 1));
    //
    var emailInput = find.byKey(const Key('login username input'));
    await tester.tap(emailInput);
    await tester.enterText(emailInput, "test@m.com");
    await tester.pumpAndSettle(const Duration(seconds: 1));
    //
    var passwordInput = find.byKey(const Key('login password input'));
    await tester.tap(passwordInput);
    await tester.enterText(passwordInput, "password");
    await tester.pumpAndSettle(const Duration(seconds: 1));
    //
    var loginButton = find.byKey(const Key('login button'));
    await tester.tap(loginButton, warnIfMissed: false);
    await tester.pumpAndSettle(const Duration(seconds: 3));
    //
    // expect(version, findsOneWidget);
    // final Finder home = find.byWidget(const HomeScreen());
    expect(find.byWidgetPredicate((widget) => widget is HomeScreen),
        findsOneWidget);
    // await tester.pumpAndSettle(const Duration(seconds: 1));

    var version = find.byWidgetPredicate(
        (widget) => widget is Text && widget.data!.contains("Version: 2.0"));
    expect(version, findsOneWidget);
    await tester.pumpAndSettle(const Duration(seconds: 3));
  });
}

我在这里做错了什么? 我试图通过互联网和文档寻找一些有用的东西,但我的手不够脏。 有人可以帮我写一个很好的集成测试,将屏幕移到另一个屏幕。 非常感谢你提前。

你的测试文件中还有两个主要方法吗? 如果是这样,您可以删除第一个(我不明白它是如何存在的):

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();
  //
  // start.main();
  login.main();
}

还尝试单步执行您的代码 - 在您的测试文件中添加一个断点,并在该测试文件仍在编辑器中按 F5(我假设您像我一样在 VSCode 中),找出哪个expect调用报告失败 - 我我猜是第二个:

expect(find.byWidgetPredicate((widget) => widget is HomeScreen),
        findsOneWidget);

尝试在该调用之前添加此代码(而不是您现有的 pumpAndSettle 调用):

  await tester.pump(const Duration(milliseconds: 4000));
  await tester.pumpAndSettle();

还要考虑这个答案中的一些想法: https : //stackoverflow.com/a/70472212/491739

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM