Flutter 在带有颤振的单元测试期间,对文件对象的操作从未完成

Flutter 在带有颤振的单元测试期间,对文件对象的操作从未完成,flutter,dart,flutter-test,dart-io,Flutter,Dart,Flutter Test,Dart Io,我正在为我的flatter应用程序编写单元测试,在读取json文件时遇到了一些问题。我的api模拟类使用了一些json文件。每当我调用File对象上的方法时,它永远不会结束,但测试会继续执行,并以错误结束,因为它没有从File对象接收数据。这是非常奇怪的,因为它只发生在从一个小部件调用的提供者调用mockapi方法时。如果我在测试中直接调用mock-api方法,它可以正常工作。 我的应用程序的结构如下:WidgetScreen调用->提供者调用->mockApi Widget Legislaca

我正在为我的flatter应用程序编写单元测试,在读取json文件时遇到了一些问题。我的api模拟类使用了一些json文件。每当我调用File对象上的方法时,它永远不会结束,但测试会继续执行,并以错误结束,因为它没有从File对象接收数据。这是非常奇怪的,因为它只发生在从一个小部件调用的提供者调用mockapi方法时。如果我在测试中直接调用mock-api方法,它可以正常工作。 我的应用程序的结构如下:WidgetScreen调用->提供者调用->mockApi

Widget Legislacao屏幕从我的提供者调用方法carregarLegislacao,该方法从我的mockApi调用方法getLegislacoes,该方法读取json文件并将结果返回给提供者,提供者随后通知我的Widget。感谢您的帮助

哦,我正在用命令运行我的测试:flattertest test/my_test.dart

下面是一些代码:

屏幕显示:

class LegislacaoScreen extends StatefulWidget {
  @override
  _LegislacaoScreenState createState() => _LegislacaoScreenState();
}

class _LegislacaoScreenState extends State<LegislacaoScreen>
    with AutomaticKeepAliveClientMixin {
  @override
  void initState() {
    super.initState();
    Future.microtask(carregarDados);
  }

  @override
  bool get wantKeepAlive => true;

  Future<void> carregarDados({bool reset = false}) async {
    try {
      final legislacaoProvider =
          Provider.of<LegislacaoProvider>(context, listen: false);

      await legislacaoProvider.carregarLegislacao(
        page: legislacaoProvider.currentPage + 1,
        reset: reset,
      );
    } catch (err) {}
  }

  Widget renderBody(legislacaoProvider) {
    if (legislacaoProvider.carregandoLegislacao &&
        legislacaoProvider.legislacoes.isEmpty &&
        !legislacaoProvider.reseting) {
      return Center(
        child: CircularProgressIndicator(),
      );
    }

    if (legislacaoProvider.erroCarregandoLegislacao) {
      return MensagemAcao(
        mensagem:
            'Houve um erro ao carregar os dados.\nPor favor tente novamente.',
        acao: () => carregarDados(reset: true),
      );
    }

    return LegislacaoLista(
      carregandoLegislacao: legislacaoProvider.carregandoLegislacao,
      legislacoes: legislacaoProvider.legislacoes,
      reseting: legislacaoProvider.reseting,
      carregarDados: carregarDados,
      isFiltroEmpty: legislacaoProvider.isFiltroEmpty,
    );
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);

    final legislacaoProvider = Provider.of<LegislacaoProvider>(context);

    return Scaffold(
      appBar: CustomAppBar(
        title: 'Legislação',
        actions: <Widget>[
          IconButton(
            icon: Icon(
              Icons.search,
              color: legislacaoProvider.isFiltroEmpty
                  ? Colors.white
                  : CustomColors.verde2,
            ),
            onPressed: () {
              Navigator.of(context)
                  .pushNamed(PesquisarLegislacaoScreen.routeName);
            },
          ),
        ],
      ),
      backgroundColor: Colors.white,
      body: renderBody(legislacaoProvider),
    );
  }
class LegislacaoProvider with ChangeNotifier {
  bool _carregandoLegislacao = true;
  bool _erroCarregandoLegislacao = false;
  List<Legislacao> legislacoes = [];
  int currentPage = 0;
  bool _reseting = false;

  LegislacaoApi _legislacaoApi;

  LegislacaoProvider({LegislacaoApi legislacaoApi})
      : _legislacaoApi = legislacaoApi ?? LegislacaoApiService();

  bool get carregandoLegislacao {
    return _carregandoLegislacao;
  }

  bool get erroCarregandoLegislacao {
    return _erroCarregandoLegislacao;
  }
  bool get reseting {
    return _reseting;
  }
  Future<void> carregarLegislacao({
    int page = 1,
    bool reset = false,
  }) async {
    try {
      _carregandoLegislacao = true;
      _erroCarregandoLegislacao = false;
      _reseting = reset;

      if (reset) {
        page = 1;
      }
      notifyListeners();
      legislacoes = await _legislacaoApi.getLegislacoes(
        page: page,
        ementa: filtro['ementa'],
        conteudo: filtro['conteudo'],
        ano: filtro['ano'],
        periodoInicialLegislacao: filtro['periodoInicialLegislacao'],
        periodoFinalLegislacao: filtro['periodoFinalLegislacao'],
        tipoLegislacao: filtro['tipoLegislacao']?.id,
        numero: filtro['numero'],
        autor: filtro['autor'],
      );
      _carregandoLegislacao = false;
      _reseting = false;
      notifyListeners();
    } catch (err) {
      print(err);
      _erroCarregandoLegislacao = true;
      _carregandoLegislacao = false;
      _reseting = false;
      notifyListeners();
      throw TaNaLeiException(err.toString());
    }
  }
}
class LegislacaoApiServiceMock extends LegislacaoApi {
  bool _fail = false;

  LegislacaoApiServiceMock();

  LegislacaoApiServiceMock.fail() : _fail = true;

  @override
  Future<List<Legislacao>> getLegislacoes({
    int page = 1,
    String conteudo,
    String ementa,
    String ano,
    DateTime periodoInicialLegislacao,
    DateTime periodoFinalLegislacao,
    int tipoLegislacao,
    String numero,
    String autor,
  }) async {
    if (_fail) {
      throw Error();
    }


    final file = File('test/data/get_legislacoes.json');
    print('step 1');
    final json = await file.readAsString();
    print('step 2 '); // <-- NEVER GETS PRINTED
    return jsonDecode(json)
        .map<Legislacao>(
          (elemento) => Legislacao.fromJson(elemento),
        )
        .toList();
  }
}
final locator = GetIt.instance;

void setupLocatorLegislacaoProvider({LegislacaoApi legislacaoApi}) {
  locator.registerLazySingleton<LegislacaoProvider>(() => LegislacaoProvider(
        legislacaoApi: legislacaoApi,
      ));
}


void main() async {
  TestWidgetsFlutterBinding.ensureInitialized();
  setupLocatorLegislacaoProvider(legislacaoApi: LegislacaoApiServiceMock());
  group('LegislacaoScreen', () {
    Widget buildWidget() {
      return ChangeNotifierProvider.value(
        value: locator<LegislacaoProvider>();,
        child: MaterialApp(
          home: LegislacaoScreen(),
          routes: routes,
        ),
      );
    }

    testWidgets('builds screen', (WidgetTester tester) async {
      final child = buildWidget();
      await tester.pumpWidget(child);

      expect(find.byWidget(child), findsOneWidget);
    });



    testWidgets('finds list when data is loaded',
        (WidgetTester tester) async {
      await tester.pumpWidget(buildWidget());

      await tester.pump();
      await tester.pump();

      expect(find.byType(LegislacaoLista), findsOneWidget);
    });
  });
}

是否有其他服务或应用程序正在写入该文件?比如可能会导致锁死的东西。另外,请张贴在结尾处收到的错误消息。@dev aentgs不允许其他服务访问该文件。问题:我应该在执行readAsString后关闭文件吗?我没有在示例中看到它。没有提到接近。我想它是在内部处理的。@dev aentgs我设法用一种变通方法来运行测试。我编辑了这篇文章。好:)。测试框架中可能存在问题。是否有其他服务或应用程序正在写入该文件?比如可能会导致锁死的东西。另外,请张贴在结尾处收到的错误消息。@dev aentgs不允许其他服务访问该文件。问题:我应该在执行readAsString后关闭文件吗?我没有在示例中看到它。没有提到接近。我想它是在内部处理的。@dev aentgs我设法用一种变通方法来运行测试。我编辑了这篇文章。好:)。可能是测试框架中的问题。
➜  ta_na_lei git:(testes) ✗ flutter test test/ui/screens/legislacao/legislacao_screen_test.dart
00:03 +0: LegislacaoScreen builds screen                                                                                                                     
dentro de mock 1
00:04 +1: LegislacaoScreen exibe circular progress indicator quando carregando legislacao e reset true                                                       
dentro de mock 1
00:04 +2: LegislacaoScreen exibe lista de legislacao quando legislacoes carregadas                                                                           
dentro de mock 1
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure object was thrown running a test:
  Expected: exactly one matching node in the widget tree
  Actual: _WidgetTypeFinder:<zero widgets with type "LegislacaoLista" (ignoring offstage widgets)>
   Which: means none were found but one was expected

When the exception was thrown, this was the stack:
#4      main.<anonymous closure>.<anonymous closure> (file:///Users/home/Projetos/casacivil/ta_na_lei/test/ui/screens/legislacao/legislacao_screen_test.dart:49:7)
<asynchronous suspension>
#5      main.<anonymous closure>.<anonymous closure> (file:///Users/home/Projetos/casacivil/ta_na_lei/test/ui/screens/legislacao/legislacao_screen_test.dart)
#6      testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:140:29)
<asynchronous suspension>
#7      testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart)
#8      TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:703:19)
<asynchronous suspension>
#11     TestWidgetsFlutterBinding._runTest (package:flutter_test/src/binding.dart:683:14)
#12     AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:1083:24)
#18     AutomatedTestWidgetsFlutterBinding.runTest (package:flutter_test/src/binding.dart:1080:15)
#19     testWidgets.<anonymous closure> (package:flutter_test/src/widget_tester.dart:133:24)
#20     Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:172:27)
<asynchronous suspension>
#21     Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart)
#22     Invoker.waitForOutstandingCallbacks.<anonymous closure> (package:test_api/src/backend/invoker.dart:246:15)
#27     Invoker.waitForOutstandingCallbacks (package:test_api/src/backend/invoker.dart:243:5)
#28     Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:170:33)
#33     Declarer.test.<anonymous closure> (package:test_api/src/backend/declarer.dart:169:13)
#34     Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart:400:30)
(elided 31 frames from class _FakeAsync, class _RawReceivePortImpl, class _Timer, dart:async, dart:async-patch, and package:stack_trace)

This was caught by the test expectation on the following line:
  file:///Users/home/Projetos/casacivil/ta_na_lei/test/ui/screens/legislacao/legislacao_screen_test.dart line 49
The test description was:
  exibe lista de legislacao quando legislacoes carregadas
════════════════════════════════════════════════════════════════════════════════════════════════════
00:04 +2 -1: LegislacaoScreen exibe lista de legislacao quando legislacoes carregadas [E]                                                                    
  Test failed. See exception logs above.
  The test description was: exibe lista de legislacao quando legislacoes carregadas

00:04 +3 -1: Some tests failed.                                                                       
await tester.runAsync(() async {
        await tester.pumpWidget(buildWidget());
        await Future.delayed(Duration(seconds: 5));

        await tester.pump(Duration(seconds: 2));

        expect(find.byType(LegislacaoLista), findsOneWidget);
      });