5

So I recently wanted to add some integration testing to the my app, and followed the official guidelines from the flutter.dev on the integration testing. I managed to run a single test, so I wanted to add another one, and this is where the problems started.

I don't know how to add another test suite in the same run, so something like

TEST 1:

  1. click button
  2. check if counter incremented

TEST2:

  1. click the button again
  2. check if counter incremented again
void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  group('Integration test', () {
    testWidgets('test 1', (WidgetTester tester) async {
      app.main();
      await tester.pumpAndSettle();

      // doing stuff here works
    });
  });
}

This is what I have working right now. I expected that moving the app.main() call before the group and simply adding another testWidgets call will work (similar to unit testing) but it doesn't:

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();
  // app.main(); <<--- moving here...
  group('Integration test', () {
    // app.main(); <<--- ... or here didn't help
    testWidgets('test 1', (WidgetTester tester) async {
      // do stuff
    });
    testWidgets('test 2', (WidgetTester tester) async {
      // how to add this? And do stuff with the same app session
    });
  });
}

EDIT: For better clarity of what I'm trying to achieve. The following are some current flutter driver tests that I have. I just want to migrate to the new api of integration_test package, without losing the names "test 1", "test 2" etc

void main() {
  group("group name", () {
    FlutterDriver driver;
    setUpAll(() async {
      driver = await FlutterDriver.connect();
    });

    tearDownAll(() async {
      if (driver != null) {
        await driver.close();
      }
    });

    test('test 1', () async {
      // do stuff with the driver
    });
    test('test 2', () async {
      // do other stuff with the driver with the same seesion
    });
    test('test 3', () async {
      // etc
    });
  });
}

3 Answers 3

3

I assume your app.main() is booting the actual app. It is not possible to boot the app just once at the start of a group. You have to boot the app within the testWidgets().

It might be useful to create a restartApp() which can be triggered at the start of every testWidgets(). This way you'll be able to start your new test fresh from the start.

You should add an UniqueKey() to the app root widget. This UniqueKey() needs to be re-generated after the restartApp(). Your app will recognise the key being changed so it will perform a reload.

testWidgets('test 1', (WidgetTester tester) async {
    restartApp();
    clickButton();
    // expect count incremented
  });

testWidgets('test 2', (WidgetTester tester) async {
    restartApp();
    clickButton();
    // expect count incremented
    clickButton();
    // expect count incremented again
  });
Sign up to request clarification or add additional context in comments.

6 Comments

You are correct, the app.main() boots the app, just like it does in the docs The restarting part is a nice idea, but does not really get me where I want to get :/ The thing is, imagine you have a complicated flow that you want to test. I would like to be able to divide this flow into multiple tests that I can name, e.g: 1. add item to cart 2. add second item to cart 3. remove first item from cart 4. submit the cart 5. expect that the cart was submitted with just the second item
So for that, I'd love to have 5 test cases described like these, so that when something fails, I will see exactly on which step it failed (instead of just having the entire flow fail)
You are acceptance testing the app, so the whole flow needs to be in the same testWidgets(). You can insert multiple expects between the steps of your flow to make sure everything is going like expected. The expect will fail if the requirements aren't met with a clear error message.
I guess then it's not really possible to migrate from the flutter_driver to integration_test package, without losing all of the information that naming each tests gives me :( (I edited the question to explain what I want to achieve better)
You can also divide the flow in multiple steps so every testWidgets() can test a small step of the whole flow. But you will have to repeat the steps necessary to get a scenario where you, for example, remove the first item.
|
1

After the first test, I've got subsequent test cases to run successfully by pumping the main app into the test, e.g.

import 'package:my_app/main.dart' as app;

testWidgets('Test 1', (WidgetTester tester) {
    app.main();
    await tester.pumpAndSettle();

    // Tests ...
});

testWidgets('Test 2', (WidgetTester tester) {
    await tester.pumpWidget(app.MyApp());
    await tester.pumpAndSettle();

    // Tests ...
});

Comments

1

Here is how I run multiple test using integration_test, the SharedPreferences data seems to be preserved between test. (doesn't work with multiple group). I just recently migrated from using raw test driver to integration_test.

You have to start the app in setUp block, and simply write the test in different testWidgets.

Note: This will throw sqlite error since there is no way to make sure the app is close and reopen and this will open a new instance for each testWidget. Let me know if anyone know how to work around this issue.

import 'package:my_app/main.dart' as app;

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  setUpAll(() {
    // this will start the app for each subsequent test
    app.main();
  });
  
  group('Smoke Test', () {
    testWidgets('Integration 1', (WidgetTester tester) async {
      ...
    });

    testWidgets('Integration 2', (WidgetTester tester) async {
     ...
    });
  );
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.