Testing Flutter Apps: Confidence and Faster Iteration

testing flutter apps

Flutter is a cross-platform application development framework. But no application is really complete without a comprehensive testing suite. In this article, I will tell you the basic principles of both unit- and widget-testing Flutter apps.

Why test?

Testing is vital when developing any serious software project. With a good test suite in place, you can make changes to any part of the code without worrying if that is going to break anything. With tests, you can run them any time and get an answer within minutes if the system is working correctly. If you, as a developer do not test your code, how can you expect your clients to test it?

Unit tests

We are going to begin with unit tests, them being the simplest ones. It is important to note that Flutter clearly separates unit tests from widget tests. Where widget tests assert on the widget tree and test the UI, unit tests are not supposed to render the UI and test purely the business logic.

To start testing your classes, you need to add the test dependency to your pubspec.yaml:

dev_dependencies:
    test: 1.14.4

Now let’s create a simple model class that we will test:

This is a simple class with 2 properties and a custom getter. Now, create a file PersonTest.dart in the test folder:

This is the simplest test example ever. Firstly, on lines 1-2 we import the test module and the Person class that we are about to test. Then, in the main method, we define a test using the test function. It will accept the name of the test and a callback function, which executes the test itself. In it, we create the person model and expect that person.name will be 'John Smith'.

test package exposes a number of assertion functions that can be used with expect, like:

expect(person, isA(Person))
expect(person, isA(String))

Here are some of the common assertions from the matcher module (built into test):

  • isEmpty
  • isList
  • isFalse/isTrue
  • isNaN
  • isNull
  • throwsException

Now, if you try running the tests (you can do it with Android Studio, Run -> Run tests), you will see that this test passes. Good job!

Widget testing

Unit tests are pretty simple: perform actions, assert on the results. When UI comes into play, everything becomes complicated. Let’s again write a simplest example possible: a widget that displays your name. We will make sure it renders correctly and shows your name on the screen.

Firstly, let’s create the widget. Add the following to your main.dart file:

Should be nothing surprising here, just a MyApp stateless widget that requires a named parameter name. After doing this, add the testing code in test/main_test.dart:

You can see that instead of importing the test package, we have to import the flutter_test one. To make it work, make sure you have this in your pubspec.yaml:

dev_dependencies:
  flutter_test:
    sdk: flutter

Now, on line 5 note how we use the testWidgets function instead of the test. It injects the WidgetTester object for you that contains some UI fixtures required for rendering. It is also asynchronous, hence the async keyword for the callback function.

On line 6 we render the UI with the pumpWidget function. It behaves exactly as you would expect, you simply pass a widget to it. After that, we create a finder, which is used to find widgets in the UI tree. We want to find the text box with the name specified. Lastly, on line 10 we expect that nameFinder will findsOneWidget. For other cases, you can also assert with findsNothing, findsWidgets (one or more) or findsNWidgets (exactly n widgets).

Closing notes

In this article I explained the foundations of testing Flutter apps, thank you for reading. In the following posts I will go into advanced testing and mocking in Flutter.

Resources

Get new content delivered to your mailbox:

leave a comment