Testing in Flutter

Sep 19 2023 · Dart 2.19.3, Flutter 3.7.6, Android Studio 2021.3.1, Visual Studio Code 1.7.4

Part 4: Getting Started With Integration Test

14. Reuse Widget Test in Integration Test

Episode complete

Play next episode

Next
About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 13. Test Quotes Page Next episode: 15. Generate Your First Golden

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Transcript: 14. Reuse Widget Test in Integration Test

In the previous episode, we discussed about widget tests. The difference between a widget test and an integration test is that the widget test runs on Console, and the integration test runs on the device. In this episode, we will learn about integration tests and will be resuing the widget tests into integration tests.

To reuse the widget test as an integration test, we first convert the widget test into a function. Then we call this function inside the integration test. Let us see how to do this.

Head over to login_widget_test.dart and create a function called loginWidgetTest and move the test code inside this function. It will look like this.

Future<void> loginWidgetTest(
    WidgetTester tester) async {
      
  MockQuotesService mockQuotesService = MockQuotesService();

  await tester.pumpWidget(
    ProviderScope(
      overrides: [
        quotesNotifierProvider
            .overrideWith((ref) => QuotesNotifier(mockQuotesService))
      ],
      child: MaterialApp(
        home: LoginScreen(),
      ),
    ),
  );

when(() => mockQuotesService.getQuotes())
      .thenAnswer((_) async => mockQuotesForTesting);
  await tester.pumpAndSettle();


  final loginText = find.byKey(loginScreenTextKey);
  final emailTextField = find.byKey(emailTextFormKey);
  final passwordTextField = find.byKey(passwordTextFormKey);
  final loginButton = find.byKey(loginButtonKey);

  expect(loginText, findsOneWidget);
  expect(emailTextField, findsOneWidget);
  expect(passwordTextField, findsOneWidget);
  expect(loginButton, findsOneWidget);



  await tester.enterText(emailTextField, 'abcd');
  await tester.enterText(passwordTextField, '1234');

  await tester.tap(loginButton);

  await tester.pumpAndSettle();
  final emailErrorText = find.text(kEmailErrorText);
  final passwordErrorText = find.text(kPasswordErrorText);

  expect(emailErrorText, findsOneWidget);
  expect(passwordErrorText, findsOneWidget);



  await tester.enterText(emailTextField, 'abcd@mail.com');
  await tester.enterText(passwordTextField, 'abcd1234');

  await tester.tap(loginButton);

  await tester.pump(const Duration(seconds: 1));
  expect(find.byKey(loginCircularProgressKey), findsOneWidget);


  await tester.pump(Duration(seconds: 1));
  expect(find.byKey(loginCircularProgressKey), findsNothing);
 
  expect(emailErrorText, findsNothing);
  expect(passwordErrorText, findsNothing);

  await tester.pumpAndSettle();

  var quotesPageTitle = find.byKey(quotesTextKey);
  expect(quotesPageTitle, findsOneWidget);

}

We will call this function inside the main function.

void main(){
    testWidgets('Login Widget Test', loginWidgetTest);
}

Run the login widget test to check if our refactor has not broken anything.

Just like we refactored the login widget test, we must do the same for the quotes widget test.

Here is a challenge for you. Pause the video and try to refactor the quotes widget test.

I hope you were able to do it. If not, here’s the solution

void main() {
  testWidgets('All Quotes Widget Test', allQuotesWidgetTest);
}

Future<void> allQuotesWidgetTest(WidgetTester tester) async {
  MockQuotesService mockQuotesService = MockQuotesService();

  void getQuotesAfter2SecondsDelay() {
    when(() => mockQuotesService.getQuotes()).thenAnswer((_) async {
      return await Future.delayed(
          const Duration(seconds: 2), () => mockQuotesForTesting);
    });
  }

  Widget createWidgetUnderTest() {
    return ProviderScope(
      overrides: [
        quotesNotifierProvider.overrideWith(
          (ref) => QuotesNotifier(mockQuotesService),
        ),
      ],
      child: MaterialApp(
        home: AllQuotesScreen(),
      ),
    );
  }

  getQuotesAfter2SecondsDelay();
  await tester.pumpWidget(createWidgetUnderTest());

  expect(find.text('All Quotes'), findsOneWidget);

  await tester.pump(const Duration(seconds: 1));
  expect(find.byKey(quotesCircularProgressKey), findsOneWidget);
  await tester.pumpAndSettle();
  expect(find.byKey(quotesCircularProgressKey), findsNothing);

  expect(find.text('Test Quote 1'), findsOneWidget);
  expect(find.text('Test Quote 2'), findsOneWidget);
  expect(find.text('Test Quote 3'), findsOneWidget);
}

Now that we have refactored the widget tests, we can reuse them in the integration test.

Create a new folder called integration_test inside the root folder. Inside this folder, create a new file called integration_test.dart.

The integration test in written inside the main function, so let’s create a main function.

void main(){
    
}

We have to create multiple widget tests to run in the integration test. So we will use the group function.

void main(){
    group('Integratoin', () {
        
    });
}

The group function runs multiple tests in a group. The first parameter is the group’s name, and the second parameter is a function containing the tests. In this group, we will run the login widget test and the quotes widget test.

testWidgets('Login-Page', (tester) => loginWidgetTest(tester));
testWidgets('All-Quotes-Page', (tester) => allQuotesWidgetTest(tester));

Before running the integration test, we must ensure our Flutter widgets are ready. So we must call the WidgetsFlutterBinding.ensureInitialized() function before running the integration test. Finally, it will look like this.

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();
  group('Integration Tests', () {
    testWidgets('Login-Page', (tester) => loginWidgetTest(tester, null));
    testWidgets('All-Quotes-Page', (tester) => allQuotesWidgetTest(tester, null));
  });
}

Now to run integration test, we need a device to run. So open emulator, simulator or just connect your device to the computer and run the following command.

flutter test integration_test/integration_tests.dart

The integration test will run on the device, and you can see the app running on the device.

This is how we can reuse the widget tests as integration tests, which saves time and effort.