Skip to content

Testing

Dustin Catap edited this page Jun 19, 2024 · 3 revisions

Naming Convention

Items Naming Pattern Target Example
Test Files {{class_name_to_be_tested}}_test.dart MainViewModel main_view_model_test.dart
Test Methods {{methodNameToBeTested}} should {{expected result}} when {{state}} openLink() openLink should trigger open uri when link text tapped

Testing Framework

  • test provides standard way of writing and running tests in Dart.
  • flutter_test for testing Flutter widgets. Read more about widget testing here.

Mocking Framework

  • mockito for creating mocks in Dart with null safety. Uses code generation.

Testing Code Style

Given that we have the following class to be tested:

class MainViewModel extends ViewModel {
  final UriHandler _uriHandler;

  MainViewModel(this._uriHandler);

  Future<void> openLink(Uri uri) async {
    await _uriHandler.openUri(uri);
  }
}

Below is an example of a unit test code:

import 'package:mockito/mockito.dart';
import 'package:test/test.dart';

import 'main_view_model_test.mocks.dart';

@GenerateNiceMocks([
  MockSpec<UriHandler>(),
])
void main() {
  group(MainViewModel, () {
    late MockUriHandler mockUriHandler;

    setUp(() {
      mockUriHandler = MockUriHandler();
    });

    MainViewModel createUnitToTest() {
      return MainViewModel(mockUriHandler);
    }

    group('openLink', () {
      test('should trigger open uri when link text tapped', () async {
        final expectedUri = Uri.parse('http://sample.com');
        when(mockUriHandler.openUri(expectedUri)).thenAnswer((_) async => true);

        final unit = createUnitToTest();
        await unit.openLink(expectedUri);

        verify(mockUriHandler.openUri(expectedUri)).called(1);
      });
    });
  });
}
  • The main enclosing group should be named after the class to be tested.
  • Create specific group for each method to be tested.
  • Create a seperate method to create the unit to be tested.
  • Seperate each part (arrange, act, assert) of the test code with a blank line for readability.
  • Run build_runner first to generate the mocks. See code generation for more details.

💡 TIP

  • Use the snippet shortcut gtest to create a test file similar above.

Code Coverage

  • There is an existing issue regarding untested files not being included in the code coverage report. As a workaround, we use full_coverage to generate a dummy file that imports all files in a specified directory. This is just to make sure all files are "included" when running the test.
  • Another thing is the code coverage of generated files. The project uses a script ignore_generated_files_from_coverage.sh to remove the generated files from the code coverage report. Before running the test with coverage, make sure to run this script first once every time you run build_runner.