Flutter unit testing – Binding has not yet been initialized

huangapple go评论82阅读模式
英文:

Flutter unit testing - Binding has not yet been initialized

问题

以下是您提供的内容的翻译部分:

"Used SharedPreference throwing error in Unit test. In one function I have used SharedPreference and during it's unit testing getting error as "Binding has not yet been initialized" and many other errors too."

在单元测试中使用SharedPreference时出现错误。在一个函数中,我使用了SharedPreference,在进行单元测试时出现错误,错误消息为“Binding has not yet been initialized”,还有许多其他错误。

"Working unit test:"
"在单元测试中正常工作:"

"After uncommenting SharedPreference code:"
"取消注释SharedPreference代码后:"

"Below is the code of my User.dart file"
"以下是我的User.dart文件的代码"

"and below is the code of test file (User_test.dart)"
"下面是测试文件的代码(User_test.dart)"

"Below is the errors I am getting."
"下面是我遇到的错误。"

"Below is the output of my flutter doctor command"
"下面是我的flutter doctor命令的输出"

英文:

Used SharedPreference throwing error in Unit test. In one function I have used SharedPreference and during it's unit testing getting error as "Binding has not yet been initialized" and many other errors too.

Working unit test:
Flutter unit testing – Binding has not yet been initialized

After uncommenting SharedPreference code:
Flutter unit testing – Binding has not yet been initialized

Below is the code of my User.dart file

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

import &#39;package:shared_preferences/shared_preferences.dart&#39;;

class User {
  final String name;

  User(this.name);
  Future&lt;bool&gt; userName() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setString(&quot;name&quot;, name);
    return true;
  }
}

<!-- end snippet -->

and below is the code of test file (User_test.dart)

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

import &#39;dart:math&#39;;

import &#39;package:flutter_test/flutter_test.dart&#39;;
import &#39;package:unit_testf/user.dart&#39;;

void main() {
  test(&quot;a unit test&quot;, () async {
    User user = User(&quot;flutter&quot;);
    final result = await user.userName();
    expect(result, true);
  });
}

<!-- end snippet -->

Below is the errors I am getting.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

Binding has not yet been initialized.
The &quot;instance&quot; getter on the ServicesBinding binding mixin is only available once that binding has been initialized.
Typically, this is done by calling &quot;WidgetsFlutterBinding.ensureInitialized()&quot; or &quot;runApp()&quot; (the latter calls the former). Typically this call is done in the &quot;void main()&quot; method. The &quot;ensureInitialized&quot; method is idempotent; calling it multiple times is not harmful. After calling that method, the &quot;instance&quot; getter will return the binding.
In a test, one can call &quot;TestWidgetsFlutterBinding.ensureInitialized()&quot; as the first line in the test&#39;s &quot;main()&quot; method to initialize the binding.
If ServicesBinding is a custom binding mixin, there must also be a custom binding class, like WidgetsFlutterBinding, but that mixes in the selected binding, and that is the class that must be constructed before using the &quot;instance&quot; getter.
package:flutter/src/foundation/binding.dart 284:9                               BindingBase.checkInstance.&lt;fn&gt;
package:flutter/src/foundation/binding.dart 366:6                               BindingBase.checkInstance
package:flutter/src/services/binding.dart 54:54                                 ServicesBinding.instance
package:flutter/src/services/platform_channel.dart 166:45                       BasicMessageChannel.binaryMessenger
package:flutter/src/services/platform_channel.dart 180:38                       BasicMessageChannel.send
package:shared_preferences_foundation/messages.g.dart 115:52                    UserDefaultsApi.getAll
package:shared_preferences_foundation/shared_preferences_foundation.dart 46:53  SharedPreferencesFoundation.getAll
package:shared_preferences/shared_preferences.dart 164:57                       SharedPreferences._getSharedPreferencesMap
package:shared_preferences/shared_preferences.dart 33:19                        SharedPreferences.getInstance
package:unit_testf/user.dart 8:55                                               User.userName
test/user_test.dart 9:31                                                        main.&lt;fn&gt;

<!-- end snippet -->

Below is the output of my flutter doctor command

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

Last login: Thu Feb 16 09:58:26 on console
anandsuthar@anands-MacBook-Air ~ % flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.3.10, on macOS 13.1 22C65 darwin-x64, locale en-GB)
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
[✓] Xcode - develop for iOS and macOS (Xcode 14.2)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2022.1)
[✓] VS Code (version 1.75.1)
[✓] Connected device (2 available)
[✓] HTTP Host Availability

• No issues found!
anandsuthar@anands-MacBook-Air ~ % 

<!-- end snippet -->

答案1

得分: 5

根据上下文,您运行的代码需要确保ServicesBinding已经初始化。

从显示一个Widget作为第一步开始,可以轻松地将其称为ServicesBinding已经初始化。但是,如果要调用需要初始化的方法/类,您必须确保通过显式调用这两个方法来初始化。

TestWidgetsFlutterBinding.ensureInitialized();

或者

WidgetsFlutterBinding.ensureInitialized();

因此,您的主要方法应该如下:

void main() async {
  // 首先调用
  WidgetsFlutterBinding.ensureInitialized();
  
  // 然后在此之后编写您的代码
  // ……
  // ……
  // ……
}
英文:

Based on context you are running you have to be sure that ServicesBinding has been initialized.

Making something which start with showing an Widget as the first thing is easily call the rest as ServicesBinding has been initialized.
But calling method/classes that have to been initialized yet you must be sure of that initialized by calling those two methods which explicitly invoking the initialize.

TestWidgetsFlutterBinding.ensureInitialized();

Or

WidgetsFlutterBinding.ensureInitialized();

So your main method have to be:

void main() async {
  // First call
  WidgetsFlutterBinding.ensureInitialized();

  // Then Your code after
  //……
  //……
  //…...
}

答案2

得分: 0

只有文本内容需要翻译,代码部分不需要翻译:

看起来你正在尝试在共享首选项上调用.getInstance()方法,但在单元测试期间无法使用,因为你试图隐式地调用其行为。
由于你只是尝试对User类进行'单元'测试,无论如何都要模拟共享首选项,因为你不测试其功能。将要测试的类与类内部使用的一切视为黑盒解决方案进行分离是一个良好的实践,这意味着你需要模拟它。

尝试查看提到的解决方案这里以了解如何模拟共享首选项的行为。

错误消息来自于你尝试在仅在实际运行Flutter应用程序时才可用的类上调用方法。由于你的单元测试不创建这个完整的环境(即每个测试都不完全构建应用程序),它会说这个类未实例化。因此,提供WidgetsFlutterBinding不会有所帮助,因为你的测试中没有实例化任何小部件。

如果有用,请告诉我!

英文:

It seems that you're trying to invoke the .getInstance() method on shared preferences, which is not available during a unit test as you implicitly try to invoke its behavior.
Since you only try to 'unit' test your User class, you want to mock the Shared Preferences anyway since you're not testing the functionality of that. It is good practice to separate the classes you test, and treat everything the class uses internally as a black-box solution, which means you will need to mock it.

Try looking into the solution mentioned here to see how to mock the Shared Preferences behavior.

The error message is coming from the fact that you're trying to invoke a method on a class that is only available during the actual running of a Flutter app. Since your unit tests do not create this complete environment (i.e. the app is not built completely for each test), it is saying this class is not instantiated. The solution of providing the WidgetsFlutterBinding is thus not going to help, as you instantiate no widgets in your test.

Let me know if it works!

huangapple
  • 本文由 发表于 2023年2月16日 17:51:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/75470485.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定