Testing In Flutter: Unit Test 🧪
What exactly is a test, and how many different types of tests are there in Flutter? What exactly is a unit test? How Do I Unit Test a Flutter App?

Search for a command to run...
What exactly is a test, and how many different types of tests are there in Flutter? What exactly is a unit test? How Do I Unit Test a Flutter App?

Hi, thanks for the through article about tests! To write and debug tests easily, with action history, time travelling, screenshots, rapid re-execution, video recordings, interactive mode and more, I have open-sourced the convenient_test. What do you think about it?
Link: GitHub repository - fzyzcjy/flutter_convenient_test
Lessons from Code, Content, and Consistency

Reliability basics: Outbox pattern + why it matters

Introducing Kafka/Redpanda + move to event-driven workflow

Connect Orders ↔ Inventory (first working service-to-service flow)

Inventory service + gRPC + proto contracts


pubspec.yaml under the dev dependencies section.root/
|- test/
|- calculator_test.dart
main method.main(){}
test package in the fileimport 'package:test/test.dart';
main(){}
test() method :test method accepts two parameters: description, which is just a text describing the test's goal, and the function, which is where we write the logic and then we compare the result with our expectation.For example, there is one class named Calculator.dart in which, there are different methods defined for calculations like, add, subtract, etc.
class Calculator{
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
return a - b;
}
int multiply(int a, int b) {
return a * b;
}
double divide(double a, double b) {
return a / b;
}
}
test function inside the main() method and write the description.import 'package:test/test.dart';
main(){
test('The result of addition should be 8 when adding 6 and 2',(){
})
}
Calculator class in order to access the methods.import 'package:test/test.dart';
main(){
test('The result of addition should be 8 when adding 6 and 2',(){
final calculator = Calculator();
})
}
expect() methodactual, matches the second object given called matcher. If that condition is not met then the expect function will throw a test failure.expect method for our test.main() {
test('The calculator returns 8 when adding 6 and 2', () {
final calculator= Calculator();
expect(calculator.add(6, 2), 8);
});
}
main() {
test('The calculator returns 8 when adding 6 and 2', () {
final calculator= Calculator();
final result = calculator.add(6,2);
expect(result,8.000001, reason: 'It should be exactly 8');
});
}
Run on VS Code.flutter pub run test

8 to 9 our test will fail. And it will throw an error shown below.
main() {
test('The calculator returns 8 when adding 6 and 2', () {
// 1st step: setup -> create the calculator object
final calculator= Calculator();
});
}
main() {
test('The calculator returns 8 when adding 6 and 2', () {
// 1st step: setup -> create the calculator object
final calculator= Calculator();
// 2nd step: side effect -> collect the result you want to test
final result = calculator.add(6,2);
});
}
main() {
test('The calculator returns 8 when adding 6 and 2', () {
// 1st step: setup -> create the calculator object
final calculator= Calculator();
// 2nd step: side effect -> collect the result you want to test
final result = calculator.add(6,2);
// 3rd step: expectation -> compare the result against and expected value
expect(result,8);
});
}
isNotNull, isNotEmpty, isNull, isEmpty, and so on.findNWidgets() to assert that we can find as many widgets as we pass as an argument (This will be further explained in Widget Testing part. So don't worry if you don't understand the below code.).findOneWidget, which exactly asserts that there’s only one widget present at that time.findsNothing.testWidgets('there is no buttons on the screen', (tester) async {
await tester.pumpWidget(const CalculatorPage());
expect(find.byType(ElevatedButton), findsNothing);
});
group() Functionmain() {
test('The calculator returns 8 when adding 6 and 2', () {
final calculator = Calculator();
expect(calculator.add(6, 2), 8);
});
test('The calculator returns 4 when subtracting 2 from 6', () {
final calculator = Calculator();
expect(calculator.subtract(6, 2), 4);
});
test('The calculator returns 8 when multiplying 4 with 2', () {
final calculator = Calculator();
expect(calculator.multiply(4, 2), 8);
});
test('The calculator returns 9 when diving 18 and 2', () {
final calculator = Calculator();
expect(calculator.divide(18, 2), 9);
});
}
group() is a function in the test library. Whose duty is to assist you in structuring the tests by grouping them with a name of your choice.main() {
group('add', () {
test('The calculator returns 8 when adding 6 and 2', () {
final calculator = Calculator();
expect(calculator.add(6, 2), 8);
});
});
group('subtract', () {
test('The calculator returns 4 when subtracting 2 from 6', () {
final calculator = Calculator();
expect(calculator.subtract(6, 2), 4);
});
});
group('multiply', () {
test('The calculator returns 8 when multiplying 4 with 2', () {
final calculator = Calculator();
expect(calculator.multiply(4, 2), 8);
});
});
group('divide', () {
test('The calculator returns 9 when diving 18 and 2', () {
final calculator= Calculator();
expect(calculator.divide(18, 2), 9);
});
});
}
divide() method in Calculator.dart.class Calculator {
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
return a - b;
}
int multiply(int a, int b) {
return a * b;
}
double divide(double a, double b) {
if (b == 0) throw ArgumentError('Cannot divide by zero');
return a / b;
}
}
group('divide', () {
//..
test('The calulator throws an Argument Error when diving by zero', () {
});
});
throwsArgumentError built-in matcher.group('divide', () {
//...
test('The calulator throws an Argument Error when diving by zero', () {
final calculator= Calculator();
expect(calculator.divide(18, 0), throwsArgumentError);
});
});
expect function may run this code within an internal try-catch statement and compare the error to our matcher.group('divide', () {
//...
test('The calulator throws an Argument Error when diving by zero', () {
final calculator= Calculator();
expect(() => calculator.divide(18, 0), throwsArgumentError);
});
});
setUp() and tearDown() MethodsetUpAll(): Runs just once before any test is executed.setUp(): Invoked before every test in a group or test suite.tearDown(): Invoked after every test even if the test has failed.tearDownAll(): Executed after all the tests have been completed.setUp method. Every single test, as you can see, creates an instance of a Calculator object and then applies the side effects.setUp function. Within this method, we'll generate a new Calculator object that we may reuse in our tests.main() {
late Calculator calculator;
setUp(() {
calculator = Calculator();
});
group('add', () {
test('The calculator returns 8 when adding 6 and 2', () {
expect(calculator.add(6, 2), 8);
});
});
group('subtract', () {
test('The calculator returns 4 when subtracting 2 from 6', () {
expect(calculator.subtract(6, 2), 4);
});
});
group('multiply', () {
test('The calculator returns 8 when multiplying 4 with 2', () {
expect(calculator.multiply(4, 2), 8);
});
});
group('divide', () {
test('The calculator returns 9 when diving 18 and 2', () {
expect(calculator.divide(18, 2), 9);
});
test('The calculator throws an Argument Error when diving by zero', () {
expect(() => calculator.divide(18, 0), throwsArgumentError);
});
});
}
async and await. Indicating that we’re waiting to receive the result.Calculator.dart file create the below method.Future<double>? squareRootOf(double a) =>
Future.delayed(const Duration(seconds: 1), () => math.sqrt(a));
group('square root', () {
test('The calculator returns 5 when the input is 25', () async {
expect(await calculator.squareRootOf(25), 5);
});
});
squareRootOf function to finish.emitInOrder() matcher inside expect method. Because the stream is going to return the values one by one in order.Stream<int> fibonacciSequence() => Stream.periodic(
const Duration(seconds: 1), (count) => _fibonacciValues[count]);
final List<int> _fibonacciValues = [0, 1, 1, 2, 3, 5, 8, 13, 21];
fibonacciSequence() is returning the Stream of type int.group('fibonacci sequence', () {
test('The calculator return [0, 1, 1, 2, 3, 5, 8, 13, 21] in order', () {
expect(calculator.fibonacciSequence(),
emitsInOrder([0, 1, 1, 2, 3, 5, 8, 13, 21]));
});
});
