I'm trying to give a value to JsonPlaceholderService().getPlaceholder()
when it's called on button click in the widget test but it fails with
StateError (Bad state: No method stub was called from within `when()`.
Was a real method called, or perhaps an extension method?)
home.dart
import 'package:flutter/material.dart';
import 'package:fluttertest/json_placeholder_service.dart';
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String text = '';
Future<void> _onPressed() async {
final response = await JsonPlaceholderService().getPlaceholder();
setState(() {
text = response.title;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
child: const Text('Get text'),
onPressed: () => _onPressed(),
),
const SizedBox(height: 40),
Text(text),
],
),
),
);
}
}
json_placeholder_model.dart
class JsonPlaceholderModel {
int id;
int userId;
String title;
bool completed;
JsonPlaceholderModel({
required this.id,
required this.userId,
required this.title,
required this.completed,
});
Map<String, dynamic> toJson() => {
'id': id,
'userId': userId,
'title': title,
'completed': completed,
};
JsonPlaceholderModel.fromJson(dynamic json)
: id = json['id'],
userId = json['userId'],
title = json['title'],
completed = json['completed'];
}
json_placeholder_service.dart
import 'dart:convert';
import 'package:fluttertest/json_placeholder_model.dart';
import 'package:http/http.dart' as http;
class JsonPlaceholderService {
Future<JsonPlaceholderModel> getPlaceholder() async {
const url = 'https://jsonplaceholder.typicode.com/todos/1';
final response = await http.get(Uri.parse(url));
final data = jsonDecode(const Utf8Decoder().convert(response.bodyBytes));
final JsonPlaceholderModel json = JsonPlaceholderModel.fromJson(data);
return json;
}
}
widget_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:fluttertest/json_placeholder_model.dart';
import 'package:fluttertest/json_placeholder_service.dart';
import 'package:fluttertest/main.dart';
import 'package:mockito/mockito.dart';
void main() {
testWidgets('Should display api text on button click',
(WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());
// Stub http request
final json = {
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
};
final response = JsonPlaceholderModel.fromJson(json);
// Methode 1 -> says to use methode 2
when(JsonPlaceholderService().getPlaceholder())
.thenReturn(Future.value(response));
// Methode 2
when(JsonPlaceholderService().getPlaceholder())
.thenAnswer((_) async => response);
// Click the button
final button = find.byType(ElevatedButton);
expect(button, findsOneWidget);
await tester.tap(button);
await tester.pumpAndSettle();
await tester.pump(const Duration(seconds: 2));
// The text is displayed
expect(find.text('delectus aut autem'), findsOneWidget);
});
}
All this code is available in this repo : https://github.com/TheSmartMonkey/flutter-http-widget-test
First init your service in your widget constructor then it could be mocked
Second mock your service
main.dart
void main() {
runApp(MyApp(client: JsonPlaceholderService()));
}
home.dart
class MyHomePage extends StatefulWidget {
final String title;
final JsonPlaceholderService client;
const MyHomePage({
Key? key,
required this.title,
required this.client,
}) : super(key: key);import 'package:flutter/material.dart';
import 'package:fluttertest/json_placeholder_service.dart';
class MyHomePage extends StatefulWidget {
final String title;
final JsonPlaceholderService client;
const MyHomePage({
Key? key,
required this.title,
required this.client,
}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String text = '';
Future<void> _onPressed() async {
final response = await widget.client.getPlaceholder();
setState(() {
text = response.title;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
child: const Text('Get text'),
onPressed: () => _onPressed(),
),
const SizedBox(height: 40),
Text(text),
],
),
),
);
}
}
widget_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:fluttertest/json_placeholder_model.dart';
import 'package:fluttertest/json_placeholder_service.dart';
import 'package:fluttertest/main.dart';
import 'package:mocktail/mocktail.dart';
class MockJsonPlaceholderService extends Mock
implements JsonPlaceholderService {}
void main() {
final mockJsonPlaceholderService = MockJsonPlaceholderService();
testWidgets('Should display api text on button click',
(WidgetTester tester) async {
// Given
// Build our app and trigger a frame.
await tester.pumpWidget(
MyApp(client: mockJsonPlaceholderService),
);
// When
// Stub http request
final json = {
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
};
final response = JsonPlaceholderModel.fromJson(json);
when(() => mockJsonPlaceholderService.getPlaceholder())
.thenAnswer((_) async => response);
// Click the button
final button = find.byType(ElevatedButton);
expect(button, findsOneWidget);
await tester.tap(button);
await tester.pumpAndSettle();
await tester.pump(const Duration(seconds: 2));
// Then
verify(() => mockJsonPlaceholderService.getPlaceholder()).called(1);
expect(find.text('delectus aut autem'), findsOneWidget);
});
}
article : https://gist.github.com/brianegan/414f6b369c534a0e5f20bff377823414
All this code is available in this repo : https://github.com/TheSmartMonkey/flutter-http-widget-test