Flutter 单元测试 - 如何测试对字段的访问是否会抛出 LateInitializationError

Flutter unit test - How to test that an access to a field throws a LateInitializationError

我想测试一个 class 延迟字段尚未初始化的地方。

这是我的测试代码:

test('Set lang method', ()  {
    // Throws an exception because the field osLang is not supposed to be initialized yet.
    expect(() => dbRepository.osLang, throwsException); 
    dbRepository.setOsLang('fr');
    expect(dbRepository.osLang, 'fr');
});

不幸的是,当我 运行 我的测试时出现这个错误:

package:test_api                                           expect
package:flutter_test/src/widget_tester.dart 455:16         expect
test/src/models/repositories/db_repository_test.dart 20:7  main.<fn>.<fn>

Expected: throws <Instance of 'Exception'>
  Actual: <Closure: () => String>
   Which: threw LateError:<LateInitializationError: Field '_osLang@19447861' has not been initialized.>
          stack package:my_app/src/models/repositories/db_repository.dart        DBRepository._osLang
                package:my_app/src/models/repositories/db_repository.dart 18:24  DBRepository.osLang
                test/src/models/repositories/db_repository_test.dart 20:33       main.<fn>.<fn>.<fn>
                package:test_api                                                 expect
                package:flutter_test/src/widget_tester.dart 455:16               expect
                test/src/models/repositories/db_repository_test.dart 20:7        main.<fn>.<fn>
                
          which is not an instance of 'Exception'

我尝试将 throwsException 更改为 throwsA(isA<LateInitializationError>),但我的 IDE 没有找到任何名为 LateInitializationError 的 class。

我在 flutter 文档中找不到解决该问题的方法,所以我在这里问一下。感谢您的回答。

Error 不是 Exception,所以 throwsException 不会匹配它。

LateInitializationError曾经是public类型,现在好像不是public了。你可以求助于 throwsA(isA<Error>())。 (基于 last available public documentation for it,它直接派生自 Error,因此没有更具体的类型可以测试。)您可以检查 Error 字符串以使其更具体:

expect(
  () => dbRepository.osLang,
  throwsA(
    predicate<Error>(
      (error) => error.toString().contains('LateInitializationError'),
    ),
  ),
);

综上所述,在我看来,LateInitializationError 的测试无论如何都可能有点问题。理想情况下 late 变量不应作为 API 的一部分公开。如果您的代码需要显式初始化步骤,那么使用描述性错误消息进行显式检查会更清楚。也就是说,而不是:

late final String someProperty;

你可以有这样的东西:

String? _someProperty;

String get someProperty {
  var _someProperty = this._someProperty;
  if (_someProperty == null) {
    throw StateError('init() must be called first');
  }
  return _someProperty;
}