Flutter Tests made simple

Kenzy Limon
5 min readOct 5, 2022

--

Bugs can take a considerable time in software development, if proper tests are not implemented in a project, future code maintainability and new feature implementations become a problem.

Typical bugs” are errors, flaws or faults in the design, development, or operation of computer software that causes it to produce an incorrect or unexpected result.

Most seasoned software developers eventually grow to become comfortable at navigating complex code and quick at fixing bugs, this is however made possible by writting proper test cases.

Programs may have bugs (unexpected behavior), programming languages may have design flaws or implementation bugs (In the case of the famous WAT).

Flutter tests are incredibly easy to write and handy when verifying the behavior of a single core function, method, or class. This is great for checking those external dependencies such as a Network, Location, Events or Database are working as expected and that the right result is provided.

What we will cover in this short meticulous article.

  1. How tests are written and structured in Flutter.
  2. Test execution and outputs.
  3. How to mock data and network requests.

To start, we begin by adding a test package inside your project pubspec.yaml under the dev dependencies section. Flutter includes a test folder on the root of the project with an example widget_test.dart file.

Every file should begin with a main method as an entry.

root_project/test/test.dart

The test() method requires two parameters:

  • Description: A string that describes the test actions implemented in the function, this could be a detailed text.
  • Function: This is where the logic resides, after which we compare the result with our expectation. you need to import package:test/test.dart
import 'package:test/test.dart';main(){  test('+ Button to increament by 1',(){

});
}

The expect() method asserts is the actual value matches the matcher value, if at one point the two values don't match the test will fail.

In case of failure, we can provide some extra information for code documentation purposes. Use detailed test descriptions, this makes it most likely to remember what each test does.

import 'package:test/test.dart';main(){
test('+ Button to increament by 1',(){
final addLogic = AddClass();
expect(addLogic.addByOne(1), 2, reason: 'Not exactly 2');
});
}

A single test can be run by just running dart test path_to/test.dart (as of Dart 2.10 - prior SDK versions must use pub run test instead of dart test).

To run unit tests, we simply have to run the below command and if every test runs well, then we will get a message on the console indicating All tests passed.

You can select specific test cases to run by name using dart test -n "+ Button to increment by 1". this will interpret the string as a regular expression.

flutter test

For more options regarding unit tests, you can execute this command:

flutter test --help

Run tests using IntelliJ or VSCode

The Flutter plugins for IntelliJ and VSCode support running tests. This is often the best option while writing tests because it provides the fastest feedback loop as well as the ability to set breakpoints.

  • IntelliJ
  1. Open the test.dart file
  2. Select the Run menu
  3. Click the Run 'tests in test.dart' option
  4. Alternatively, use the appropriate keyboard shortcut for your platform.
  • VSCode
  1. Open the test.dart file
  2. Select the Run menu
  3. Click the Start Debugging option
  4. Alternatively, use the appropriate keyboard shortcut for your platform.

The test runner will consider any file that ends with _test.dart in the test/ folder of your root directory to be a test file. If you don't pass any paths, it will run all the test files in that directory, making it easy to test your entire application at once.

In situations which are a bit complicated for validation tests and which may require you to go beyond just comparing two objects, Dart provides the Matcher library, which is inclusive in the test framework.

Matcher library includes essential matchers such as isNull, isNotNull,isEmpty,isNotEmpty and many more. A type matcher subclass to validate the type of our results. Read more about matchers on of matchers in matcher.dart page.

The group() method allows tests to be grouped together, this is common in situations where the tests serve the same purpose/object.

main() {  group('add logics tests', () {    test('Add value by 1', () {    });    test('Add value by 2', () {    });  });}

Tests should be short and precise, this should make it easy for any developer to recognise the test functions at first glance. Long functions that require scrolling tend to be a bit messy.

The setUpAll() method runs once before tests are executed.

The setUp() method is called before every test in a group or a single test.

The tearDown() method is called after each test even if the test has failed.

The tearDownAll()method is executed after all tests have been completed.

You can use the setUp() and tearDown() methods to share code between tests. The setUp() callback will run before every test in a group or test suite, and tearDown() will run after. tearDown() will run even if a test fails, to ensure that it has a chance to clean up after itself.

Your code should continue to work as you build on more features or when you modify existing functionality, to achieve this tests have to be done during the development process, although does not mean the software has no bugs. It just implies that the software does not have any typical bugs.

Thank you for spending time reading this article, I hope you enjoyed what you read and learned something. If you have any feedback, kindly leave them in the comments.

Want to keep in touch online? Medium | Twitter | Instagram | Behance

--

--