Skip to content
Snippets Groups Projects
Commit 63b01bc9 authored by Adrien BONNIN's avatar Adrien BONNIN
Browse files

:sparkles: Ajout des tests pour le overrides

parent 5455f3a4
No related branches found
No related tags found
No related merge requests found
Pipeline #79043 passed
......@@ -31,6 +31,7 @@ migrate_working_dir/
.pub-cache/
.pub/
/build/
*.mocks.dart
# Web related
lib/generated_plugin_registrant.dart
......
......@@ -7,6 +7,8 @@ test:flutter:
stage: test
image: cirrusci/flutter
script:
- flutter pub get
- flutter pub run build_runner build --delete-conflicting-outputs
- flutter test
build:web-main:
......
# Riverpod par la pratique
* [Découverte des bases](docs/01_decouverte_des_bases.md)
* [Intégration avec Flutter](docs/02_integration_avec_flutter.md)
\ No newline at end of file
* [Intégration avec Flutter](docs/02_integration_avec_flutter.md)
## Environnement de développement
Récupérer les dépendances :
```shell script
$ flutter pub get
```
Lancer le générateur de code :
```shell script
$ flutter pub run build_runner build --delete-conflicting-outputs
```
\ No newline at end of file
......@@ -48,6 +48,7 @@ class App extends StatelessWidget {
GoRoute(
path: example.path,
builder: (_, __) => ExampleScreen(example),
parentNavigatorKey: _rootNavigatorKey,
),
],
),
......
......@@ -130,17 +130,6 @@ class TodosChangeNotifier extends ChangeNotifier {
}
}
class MutableTodosChangeNotifier extends ChangeNotifier {
MutableTodosChangeNotifier(this.todos);
final List<Todo> todos;
void updateTodo(Todo updatedTodo) {
todos.updateTodo(updatedTodo);
notifyListeners();
}
}
const todos = [
Todo(
id: 0,
......@@ -200,12 +189,4 @@ extension TodoListExtension on List<Todo> {
List<Todo> copyWithTodo(Todo updatedTodo) => //
[for (Todo todo in this) todo.id == updatedTodo.id ? updatedTodo : todo];
void updateTodo(Todo updatedTodo) {
for (int i = 0; i < length; i++) {
if (this[i].id == updatedTodo.id) {
this[i] = updatedTodo;
}
}
}
}
```dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class TodoExample extends StatelessWidget {
const TodoExample({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const ProviderScope(
child: TodoList(),
);
}
}
class TodoList extends ConsumerStatefulWidget {
const TodoList({Key? key}) : super(key: key);
@override
ConsumerState<TodoList> createState() => _TodoListState();
}
class _TodoListState extends ConsumerState<TodoList> {
bool _isUncheckedFilter = false;
@override
Widget build(BuildContext context) {
final todos = ref.watch(todosProvider.select((tds) => tds.whereTodos(_isUncheckedFilter)));
return Column(
children: [
TodoListFilter(
filter: _isUncheckedFilter,
onFilterChanged: _onFilterChanged,
),
const Divider(height: 1),
Expanded(
child: ListView.builder(
itemBuilder: (_, index) =>
TodoListItem(
todos[index],
onCheckedChanged: (value) => _onCheckedChanged(todos[index], value),
),
itemCount: todos.length,
),
),
],
);
}
void _onFilterChanged(bool value) {
setState(() => _isUncheckedFilter = value);
}
void _onCheckedChanged(Todo todo, bool? value) {
final updatedTodo = todo.copyWith(checked: value != null && value);
final todos = ref.read(todosProvider.notifier).state;
ref.read(todosProvider.notifier).state = todos.copyWithTodo(updatedTodo);
}
}
class TodoListFilter extends StatelessWidget {
const TodoListFilter({
Key? key,
required this.filter,
required this.onFilterChanged,
}) : super(key: key);
final bool filter;
final ValueChanged<bool> onFilterChanged;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text("Unchecked"),
Switch(
value: filter,
onChanged: onFilterChanged,
),
],
),
);
}
}
class TodoListItem extends StatelessWidget {
const TodoListItem(this.todo, {
Key? key,
this.onCheckedChanged,
}) : super(key: key);
final Todo todo;
final ValueChanged<bool?>? onCheckedChanged;
@override
Widget build(BuildContext context) {
return CheckboxListTile(
value: todo.checked,
onChanged: onCheckedChanged,
title: Text(
todo.title,
overflow: TextOverflow.ellipsis,
),
controlAffinity: ListTileControlAffinity.leading,
);
}
}
final todosProvider = StateProvider<List<Todo>>((ref) => todos);
const todos = [
Todo(
id: 0,
title: 'Unit test passed',
checked: true,
),
Todo(
id: 1,
title: 'Code reviewed',
checked: true,
),
Todo(
id: 2,
title: 'Acceptance criteria for each issue met',
),
Todo(
id: 3,
title: 'Functional tests passed',
),
Todo(
id: 4,
title: 'Non-functional requirements met',
),
Todo(
id: 5,
title: 'Product owner accepts the User Story',
),
];
class Todo {
const Todo({
required this.id,
required this.title,
this.checked = false,
});
final int id;
final String title;
final bool checked;
Todo copyWith({
int? id,
String? title,
bool? checked,
}) {
return Todo(
id: id ?? this.id,
title: title ?? this.title,
checked: checked ?? this.checked,
);
}
}
extension TodoListExtension on List<Todo> {
List<Todo> whereTodos(bool isUnchecked) => //
where((todo) => !isUnchecked || !todo.checked).toList();
List<Todo> copyWithTodo(Todo updatedTodo) => //
[for (Todo todo in this) todo.id == updatedTodo.id ? updatedTodo : todo];
}
```
\ No newline at end of file
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
url: "https://pub.dartlang.org"
source: hosted
version: "47.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "4.7.0"
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.1"
async:
dependency: transitive
description:
......@@ -15,6 +36,62 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
build:
dependency: transitive
description:
name: build
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.1"
build_config:
dependency: transitive
description:
name: build_config
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
build_daemon:
dependency: transitive
description:
name: build_daemon
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
build_resolvers:
dependency: transitive
description:
name: build_resolvers
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.10"
build_runner:
dependency: "direct dev"
description:
name: build_runner
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
url: "https://pub.dartlang.org"
source: hosted
version: "7.2.4"
built_collection:
dependency: transitive
description:
name: built_collection
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.1"
built_value:
dependency: transitive
description:
name: built_value
url: "https://pub.dartlang.org"
source: hosted
version: "8.4.1"
characters:
dependency: transitive
description:
......@@ -29,6 +106,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.1"
checked_yaml:
dependency: transitive
description:
name: checked_yaml
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
clock:
dependency: transitive
description:
......@@ -36,6 +120,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
code_builder:
dependency: transitive
description:
name: code_builder
url: "https://pub.dartlang.org"
source: hosted
version: "4.3.0"
collection:
dependency: transitive
description:
......@@ -43,6 +134,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.16.0"
convert:
dependency: transitive
description:
name: convert
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.2"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.2"
cupertino_icons:
dependency: "direct main"
description:
......@@ -50,6 +155,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
dart_style:
dependency: transitive
description:
name: dart_style
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.4"
fake_async:
dependency: transitive
description:
......@@ -57,6 +169,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
file:
dependency: transitive
description:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.4"
fixnum:
dependency: transitive
description:
name: fixnum
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
flutter:
dependency: "direct main"
description: flutter
......@@ -86,6 +212,20 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
glob:
dependency: transitive
description:
name: glob
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
go_router:
dependency: "direct main"
description:
......@@ -93,6 +233,34 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "4.5.0"
graphs:
dependency: transitive
description:
name: graphs
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.1"
http_parser:
dependency: transitive
description:
name: http_parser
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.1"
io:
dependency: transitive
description:
name: io
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
js:
dependency: transitive
description:
......@@ -100,6 +268,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.4"
json_annotation:
dependency: transitive
description:
name: json_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "4.6.0"
lints:
dependency: transitive
description:
......@@ -135,6 +310,27 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.0"
mime:
dependency: transitive
description:
name: mime
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
mockito:
dependency: "direct dev"
description:
name: mockito
url: "https://pub.dartlang.org"
source: hosted
version: "5.3.1"
package_config:
dependency: transitive
description:
name: package_config
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
path:
dependency: transitive
description:
......@@ -142,6 +338,27 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.1"
pool:
dependency: transitive
description:
name: pool
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.1"
pub_semver:
dependency: transitive
description:
name: pub_semver
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
riverpod:
dependency: transitive
description:
......@@ -149,11 +366,32 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0-dev.9"
shelf:
dependency: transitive
description:
name: shelf
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.2"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
source_gen:
dependency: transitive
description:
name: source_gen
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.3"
source_span:
dependency: transitive
description:
......@@ -182,6 +420,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
stream_transform:
dependency: transitive
description:
name: stream_transform
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
string_scanner:
dependency: transitive
description:
......@@ -203,6 +448,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.9"
timing:
dependency: transitive
description:
name: timing
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.1"
vector_math:
dependency: transitive
description:
......@@ -210,6 +469,27 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
watcher:
dependency: transitive
description:
name: watcher
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.0"
yaml:
dependency: transitive
description:
name: yaml
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.1"
sdks:
dart: ">=2.17.1 <3.0.0"
flutter: ">=3.0.0"
......@@ -47,6 +47,8 @@ dev_dependencies:
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^2.0.0
mockito: ^5.1.0
build_runner: ^2.1.10
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
......
import 'package:article_flutter_riverpod/presentation/07_overrides_example.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import '07_overrides_test.mocks.dart';
@GenerateMocks([TodosRepository])
void main() {
group('TodoExample', () {
testWidgets('doit vérifier', (tester) async {
// given:
const mocksTodos = [
Todo(id: 0, title: 'Test'),
];
// and:
final mockTodosRepository = MockTodosRepository();
when(mockTodosRepository.getTodos()).thenReturn(mocksTodos);
// when:
await tester.pumpWidget(
ProviderScope(
overrides: [
todosRepositoryProvider.overrideWithValue(mockTodosRepository),
],
child: const MaterialApp(
home: Material(
child: TodoList(),
),
),
),
);
// then:
expect(find.byType(TodoListItem), findsOneWidget);
});
});
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment