Some people love testing apps, I haven’t met any myself, but I hear some do. I personally don’t mind unit testing, especially in Android as Junit and Mockito are just easy to use. UI testings, urgh, espresso is painful, and most companies seem to want a cross platform solution like Appium. So lets take a look at unit testing, some widget testing, and finally UI testing on a Flutter project…
Unit Testing
With unit testing, I found it very similar to Junit and Mockito. It uses the flutter_test
library, and the mockito
library.
A unit test file could look something like this:
- Each test class has to be named
your_class_name_test.dart
this will ensure that they are run when executingflutter test
setUp
will execute before each test inside the filesetUpAll
will execute once before all teststearDown
will execute after each test inside the filetearDownAll
will execute once after all teststest
can be synchronous or asynchronous depending on what is needed.
Mocking and Assertions
As Dart doesn’t have reflection (well Flutter Dart doesn’t), it’s not quite as easy as in Java / Kotlin world to make mocks. But thanks to the mockito
library and build_runner
it’s also not hard.
Simply just add an annotation for @GenerateMocks
and list the classes you want to mock. After you’ve added them run the following command
flutter pub run build_runner build
This will generate mock classes for you. So now MockFirebaseAuth
and MockUser
exist, and can be used inside tests.
So lets look at some simple mocking:
As you can see we pass our MockFirebaseAuth
into the MyAuth
constructor. Now we’re able to control what a function returns, verify that functions were called. We’re also able to use argument matchers and captures, full details can be found here https://pub.dev/packages/mockito
Assertions
Flutter uses expect(actual, matcher)
so in the example above we expect the user returned from getCurrentUser
to be equal to mockUser
as that is what we returned from MockFirebaseAuth.
There are many matchers that can be used like:
hasLength
— for checking a lists length for examplecontainsValue
— for checking a map has a specific valueisNull
— for checking a value is null
many many more can be found here https://api.flutter.dev/flutter/flutter_test/flutter_test-library.html
Integration Testing / Widget Testing
As everything in Flutter is a Widget, Widget testing means we can test UI logic without the need for a device / emulator. We can test an individual component, a page, or even the entire app (as that too is a widget).
The test file looks very similar, and can be inside the same file as general unit tests if you wanted:
Instead of using test
we use testWidgets
which provides a WidgetTester.
So lets create a simple page, and try and test a few things:
A simple page, with an AppBar
and an ElevatedButton
. When the button is pressed we set the pageTitle
triggering a rebuild and that String to be used in the AppBar
- The first test adds the
MainPage
to an app, so it can be tested. Then searches for “Not set” and expects to find this once in the page - The second test adds the
MainPage
widget again. This time taps theElevatedButton
. Now it callstester.pump()
to make sure that the state change takes effect, and then expects to find “Hello World” once in the page.
These are very simple tests, but you can test a lot with Widget Tests and gain a lot of test confidence in the app.
More information on widget testing can be found here https://docs.flutter.dev/cookbook/testing/widget/introduction.
UI Testing
Very simply, just do the same as the Widget Tests but create the files in the integration_test
folder. Instead of starting a widget, start the app itself…
In this test I’m testing one of my own Flutter apps. Clicking on “Host a session” should show a login bottom sheet…
- We start the app
- Use
pumpAndSettle
to make sure that all animations have finished - Tap on the “Host a session” button
- Expect a Widget with type
LoginBottomSheetContent
to be visible
Appium
At the moment, Appium doesn’t support Flutter apps itself. However, there does seem to be support from the community. Browserstack have a page advising how to use this here https://www.browserstack.com/guide/test-flutter-apps-with-appium
As I’m not an Appium developer, I’m not going to attempt this.
Again, it appears that Flutter have developed with hindsight. Unit testing is well thought out, Widget testing is very powerful, and UI testing also just as good.