Skip to content

Commit

Permalink
Merge pull request #20 from samuelematias/lesson20
Browse files Browse the repository at this point in the history
Lesson 20: Stubbing asynchronous methods using mockito
  • Loading branch information
samuelematias committed Dec 2, 2020
2 parents 2c6b038 + e9c92d9 commit 260038c
Show file tree
Hide file tree
Showing 7 changed files with 229 additions and 23 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ Calculator - [Caster.IO](https://caster.io) project to showcase testing techniqu

[Lesson 19: Stubbing synchronous methods with mock](https://caster.io/lessons/lesson-19-stubbing-synchronous-methods-with-mockito) 馃憠馃従 [Branch](https://github.com/samuelematias/calculator_app/tree/lesson19)

[Lesson 20: Stubbing asynchronous methods using mockito](https://caster.io/lessons/lesson-20-stubbing-asynchronous-methods-using-mockito) 馃憠馃従 [Branch](https://github.com/samuelematias/calculator_app/tree/lesson20)

## License

```
Expand Down
52 changes: 30 additions & 22 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import 'package:calculator_app/models/models.dart';
import 'package:calculator_app/pi.dart';
import 'package:calculator_app/power_of_two.dart';
import 'package:calculator_app/two_digit_operation.dart';
import 'package:flutter/material.dart';
import 'package:calculator/calculator.dart';
Expand All @@ -17,28 +19,34 @@ class CalculatorApp extends StatelessWidget {
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(12),
child: Column(
children: [
TwoDigitOperation(
calculator: calculator,
operation: Operations.add,
),
Divider(),
TwoDigitOperation(
calculator: calculator,
operation: Operations.substract,
),
Divider(),
TwoDigitOperation(
calculator: calculator,
operation: Operations.multiply,
),
Divider(),
TwoDigitOperation(
calculator: calculator,
operation: Operations.divide,
),
],
child: SafeArea(
child: Column(
children: [
PowerOfTwo(calculator: calculator),
Divider(),
Pi(calculator: calculator),
Divider(),
TwoDigitOperation(
calculator: calculator,
operation: Operations.add,
),
Divider(),
TwoDigitOperation(
calculator: calculator,
operation: Operations.substract,
),
Divider(),
TwoDigitOperation(
calculator: calculator,
operation: Operations.multiply,
),
Divider(),
TwoDigitOperation(
calculator: calculator,
operation: Operations.divide,
),
],
),
),
),
),
Expand Down
37 changes: 37 additions & 0 deletions lib/pi.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import 'package:calculator/calculator.dart';
import 'package:flutter/material.dart';

class Pi extends StatelessWidget {
Pi({Key key, @required Calculator calculator})
: assert(calculator != null),
_calculator = calculator,
super(key: key);

final Calculator _calculator;

@override
Widget build(BuildContext context) {
String _result;

return StreamBuilder<double>(
stream: _calculator.pi(),
initialData: null,
builder: (context, snapshot) {
if (snapshot.data != null) {
_result = snapshot.data.toString();
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_result != null
? 'The latest known value of pi is $_result'
: 'Calculating pi...',
style: Theme.of(context).textTheme.headline5,
),
],
);
},
);
}
}
70 changes: 70 additions & 0 deletions lib/power_of_two.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import 'package:calculator/calculator.dart';
import 'package:flutter/material.dart';

class PowerOfTwo extends StatefulWidget {
const PowerOfTwo({
Key key,
@required Calculator calculator,
}) : assert(calculator != null),
_calculator = calculator,
super(key: key);

final Calculator _calculator;

@override
State<StatefulWidget> createState() => _PowerOfTwoState();
}

class _PowerOfTwoState extends State<PowerOfTwo> {
final _controller = TextEditingController();

String _result;

@override
void initState() {
super.initState();
_controller.addListener(_getResult);
}

@override
void dispose() {
_controller.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
key: const Key('textField_powerOfTwo'),
controller: _controller,
keyboardType: TextInputType.number,
),
Text(
'to the power of two',
style: Theme.of(context).textTheme.headline5,
),
Text(
'is ${_result ?? '???'}',
style: Theme.of(context).textTheme.headline5,
),
],
);
}

void _getResult() async {
try {
final input = double.tryParse(_controller.text);
final powerOfTwoResult = await widget._calculator.powerOfTwo(input);
setState(() {
_result = powerOfTwoResult.toString();
});
} catch (_) {
setState(() {
_result = null;
});
}
}
}
7 changes: 6 additions & 1 deletion packages/calculator/lib/src/calculator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,10 @@ class Calculator {
Future<double> powerOfTwo(double a) =>
Future.delayed(const Duration(seconds: 1), () => a * a);

Stream<double> pi() => Stream.fromIterable([3, 3.1, 3.14, 3.141, 3.1415]);
Stream<double> pi() => Stream.periodic(
const Duration(seconds: 1),
(count) => _piValues[count],
);

List<double> _piValues = [3, 3.1, 3.14, 3.141, 3.1415];
}
49 changes: 49 additions & 0 deletions test/pi_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import 'package:calculator/calculator.dart';
import 'package:calculator_app/pi.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';

class MockCalculator extends Mock implements Calculator {}

void main() {
Calculator calculator;

setUp(() {
calculator = MockCalculator();
});

group('Pi', () {
testWidgets('renders the result provided by the calculator',
(tester) async {
when(calculator.pi()).thenAnswer((realInvocation) => Stream.periodic(
Duration(milliseconds: 400),
(eventIndex) {
if (eventIndex == 0) return 3.1;
if (eventIndex == 1) return 3.14;
return null;
},
));
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Pi(
calculator: calculator,
),
),
),
);
expect(find.text('Calculating pi...'), findsOneWidget);
await tester.pumpAndSettle(Duration(milliseconds: 400));
expect(
find.text('The latest known value of pi is 3.1'),
findsOneWidget,
);
await tester.pumpAndSettle(Duration(milliseconds: 400));
expect(
find.text('The latest known value of pi is 3.14'),
findsOneWidget,
);
});
});
}
35 changes: 35 additions & 0 deletions test/power_of_two_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import 'package:calculator/calculator.dart';
import 'package:calculator_app/power_of_two.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';

class MockCalculator extends Mock implements Calculator {}

void main() {
Calculator calculator;

setUp(() {
calculator = MockCalculator();
});

group('PowerOfTwo', () {
testWidgets('renders the result provided by the calculator',
(tester) async {
when(calculator.powerOfTwo(5))
.thenAnswer((realInvocation) => Future.value(100));
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: PowerOfTwo(
calculator: calculator,
),
),
),
);
await tester.enterText(find.byKey(Key('textField_powerOfTwo')), '5');
await tester.pumpAndSettle();
expect(find.text('is 100.0'), findsOneWidget);
});
});
}

0 comments on commit 260038c

Please sign in to comment.