Skip to content

Commit bd4a88d

Browse files
committed
core(*): implement movie db without any tests
1 parent 1a472dd commit bd4a88d

27 files changed

+1066
-222
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,5 @@ lib/generated_plugin_registrant.dart
3434

3535
# Exceptions to above rules.
3636
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
37+
38+
coverage/

README.md

+12-9
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
# flutter_movie_deep_dive_test
22

3-
A new Flutter project.
3+
Testing Flutter Applications
44

5-
## Getting Started
5+
## Don't forget to test your Dart Code
66

7-
This project is a starting point for a Flutter application.
7+
Testing is one of the most important things during the software development.
88

9-
A few resources to get you started if this is your first Flutter project:
9+
One of the beauty of the Dart Ecosystem, is the way developers can easily test their code.
1010

11-
- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
12-
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
11+
Flutter has 3 types of tests.
1312

14-
For help getting started with Flutter, view our
15-
[online documentation](https://flutter.dev/docs), which offers tutorials,
16-
samples, guidance on mobile development, and a full API reference.
13+
- Unit tests are the one used for testing a method, or class.
14+
- Widget tests are the tests for controlling single widget.
15+
- Integration tests are tests the large scale or all of the application.
16+
17+
## Purpose
18+
19+
Through a flutter movie application , this project demonstrate how to implement **unit** , **widgets** and **integration** tests in your application.

android/.project

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<projectDescription>
3+
<name>android__</name>
4+
<comment>Project android__ created by Buildship.</comment>
5+
<projects>
6+
</projects>
7+
<buildSpec>
8+
<buildCommand>
9+
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
10+
<arguments>
11+
</arguments>
12+
</buildCommand>
13+
</buildSpec>
14+
<natures>
15+
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
16+
</natures>
17+
</projectDescription>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
connection.project.dir=
2+
eclipse.preferences.version=1

assets/devfest.jpeg

95.3 KB
Loading

coverage.sh

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
## ONLY FOR MAC OR LINUX
2+
3+
4+
# Install https://pub.dev/packages/remove_from_coverage
5+
pub global activate remove_from_coverage
6+
7+
# Effective test coverage
8+
flutter test --coverage
9+
10+
# Remove Generate dart files
11+
remove_from_coverage -f coverage/lcov.info -r '.g.dart$'
12+
13+
# Generate coverage info
14+
genhtml -o coverage coverage/lcov.info
15+
16+
# Open to see coverage info
17+
open coverage/index.html

ios/Runner.xcodeproj/project.pbxproj

+1-13
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,7 @@
99
/* Begin PBXBuildFile section */
1010
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
1111
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
12-
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
13-
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
1412
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
15-
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
16-
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
1713
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
1814
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
1915
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
@@ -26,8 +22,6 @@
2622
dstPath = "";
2723
dstSubfolderSpec = 10;
2824
files = (
29-
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
30-
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
3125
);
3226
name = "Embed Frameworks";
3327
runOnlyForDeploymentPostprocessing = 0;
@@ -38,13 +32,11 @@
3832
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
3933
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
4034
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
41-
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
4235
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
4336
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
4437
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
4538
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
4639
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
47-
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
4840
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
4941
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
5042
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -57,8 +49,6 @@
5749
isa = PBXFrameworksBuildPhase;
5850
buildActionMask = 2147483647;
5951
files = (
60-
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
61-
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
6252
);
6353
runOnlyForDeploymentPostprocessing = 0;
6454
};
@@ -68,9 +58,7 @@
6858
9740EEB11CF90186004384FC /* Flutter */ = {
6959
isa = PBXGroup;
7060
children = (
71-
3B80C3931E831B6300D905FE /* App.framework */,
7261
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
73-
9740EEBA1CF902C7004384FC /* Flutter.framework */,
7462
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7563
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
7664
9740EEB31CF90195004384FC /* Generated.xcconfig */,
@@ -201,7 +189,7 @@
201189
);
202190
runOnlyForDeploymentPostprocessing = 0;
203191
shellPath = /bin/sh;
204-
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
192+
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
205193
};
206194
9740EEB61CF901F6004384FC /* Run Script */ = {
207195
isa = PBXShellScriptBuildPhase;

lib/main.dart

+8-110
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,9 @@
11
import 'package:flutter/material.dart';
2-
3-
void main() => runApp(MyApp());
4-
5-
class MyApp extends StatelessWidget {
6-
// This widget is the root of your application.
7-
@override
8-
Widget build(BuildContext context) {
9-
return MaterialApp(
10-
title: 'Flutter Demo',
11-
theme: ThemeData(
12-
// This is the theme of your application.
13-
//
14-
// Try running your application with "flutter run". You'll see the
15-
// application has a blue toolbar. Then, without quitting the app, try
16-
// changing the primarySwatch below to Colors.green and then invoke
17-
// "hot reload" (press "r" in the console where you ran "flutter run",
18-
// or simply save your changes to "hot reload" in a Flutter IDE).
19-
// Notice that the counter didn't reset back to zero; the application
20-
// is not restarted.
21-
primarySwatch: Colors.blue,
22-
),
23-
home: MyHomePage(title: 'Flutter Demo Home Page'),
24-
);
25-
}
26-
}
27-
28-
class MyHomePage extends StatefulWidget {
29-
MyHomePage({Key key, this.title}) : super(key: key);
30-
31-
// This widget is the home page of your application. It is stateful, meaning
32-
// that it has a State object (defined below) that contains fields that affect
33-
// how it looks.
34-
35-
// This class is the configuration for the state. It holds the values (in this
36-
// case the title) provided by the parent (in this case the App widget) and
37-
// used by the build method of the State. Fields in a Widget subclass are
38-
// always marked "final".
39-
40-
final String title;
41-
42-
@override
43-
_MyHomePageState createState() => _MyHomePageState();
44-
}
45-
46-
class _MyHomePageState extends State<MyHomePage> {
47-
int _counter = 0;
48-
49-
void _incrementCounter() {
50-
setState(() {
51-
// This call to setState tells the Flutter framework that something has
52-
// changed in this State, which causes it to rerun the build method below
53-
// so that the display can reflect the updated values. If we changed
54-
// _counter without calling setState(), then the build method would not be
55-
// called again, and so nothing would appear to happen.
56-
_counter++;
57-
});
58-
}
59-
60-
@override
61-
Widget build(BuildContext context) {
62-
// This method is rerun every time setState is called, for instance as done
63-
// by the _incrementCounter method above.
64-
//
65-
// The Flutter framework has been optimized to make rerunning build methods
66-
// fast, so that you can just rebuild anything that needs updating rather
67-
// than having to individually change instances of widgets.
68-
return Scaffold(
69-
appBar: AppBar(
70-
// Here we take the value from the MyHomePage object that was created by
71-
// the App.build method, and use it to set our appbar title.
72-
title: Text(widget.title),
73-
),
74-
body: Center(
75-
// Center is a layout widget. It takes a single child and positions it
76-
// in the middle of the parent.
77-
child: Column(
78-
// Column is also a layout widget. It takes a list of children and
79-
// arranges them vertically. By default, it sizes itself to fit its
80-
// children horizontally, and tries to be as tall as its parent.
81-
//
82-
// Invoke "debug painting" (press "p" in the console, choose the
83-
// "Toggle Debug Paint" action from the Flutter Inspector in Android
84-
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
85-
// to see the wireframe for each widget.
86-
//
87-
// Column has various properties to control how it sizes itself and
88-
// how it positions its children. Here we use mainAxisAlignment to
89-
// center the children vertically; the main axis here is the vertical
90-
// axis because Columns are vertical (the cross axis would be
91-
// horizontal).
92-
mainAxisAlignment: MainAxisAlignment.center,
93-
children: <Widget>[
94-
Text(
95-
'You have pushed the button this many times:',
96-
),
97-
Text(
98-
'$_counter',
99-
style: Theme.of(context).textTheme.display1,
100-
),
101-
],
102-
),
103-
),
104-
floatingActionButton: FloatingActionButton(
105-
onPressed: _incrementCounter,
106-
tooltip: 'Increment',
107-
child: Icon(Icons.add),
108-
), // This trailing comma makes auto-formatting nicer for build methods.
109-
);
110-
}
111-
}
2+
import 'package:http/http.dart' show Client;
3+
import 'package:flutter_movie_deep_dive_test/src/app.dart';
4+
import 'package:flutter_movie_deep_dive_test/src/providers/providers.dart';
5+
6+
void main() => runApp(AppProvider(
7+
httpClient: Client(),
8+
child: MyApp(),
9+
));

lib/src/app.dart

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_bloc/flutter_bloc.dart';
3+
import 'package:flutter_movie_deep_dive_test/src/blocs/blocs.dart';
4+
import 'package:flutter_movie_deep_dive_test/src/services/services.dart';
5+
import 'package:flutter_movie_deep_dive_test/src/widgets/widgets.dart';
6+
import 'package:provider/provider.dart';
7+
8+
class MyApp extends StatelessWidget {
9+
@override
10+
Widget build(BuildContext context) {
11+
return MaterialApp(
12+
title: 'MoviesDB for Testing',
13+
theme: ThemeData(primarySwatch: Colors.blue),
14+
home: BlocProvider(
15+
builder: (context) => AppBloc(
16+
service: Provider.of<AppService>(
17+
context,
18+
listen: false,
19+
),
20+
),
21+
child: MyHomePage(title: 'Flutter Testing Tutorial'),
22+
),
23+
);
24+
}
25+
}

lib/src/blocs/app_bloc.dart

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import 'package:bloc/bloc.dart';
2+
import 'package:meta/meta.dart';
3+
import 'package:flutter_movie_deep_dive_test/src/blocs/blocs.dart';
4+
import 'package:flutter_movie_deep_dive_test/src/services/services.dart';
5+
6+
class AppBloc extends Bloc<AppEvent, AppState> {
7+
final AppService service;
8+
final AppState initWithState;
9+
10+
AppBloc({@required this.service, this.initWithState});
11+
12+
@override
13+
AppState get initialState =>
14+
initWithState == null ? AppEmpty() : initWithState;
15+
16+
@override
17+
Stream<AppState> mapEventToState(AppEvent event) async* {
18+
//
19+
// FETCH
20+
//
21+
if (event is FetchEvent) {
22+
yield AppLoading();
23+
try {
24+
final list = await service.loadMovies();
25+
yield AppLoaded(response: list);
26+
} catch (e) {
27+
print(e);
28+
yield AppError();
29+
}
30+
}
31+
}
32+
}

lib/src/blocs/app_event.dart

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
abstract class AppEvent {}
2+
3+
class FetchEvent extends AppEvent {
4+
final region;
5+
6+
FetchEvent({this.region});
7+
}

lib/src/blocs/app_state.dart

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import 'package:equatable/equatable.dart';
2+
import 'package:flutter/material.dart';
3+
import 'package:flutter_movie_deep_dive_test/src/models/models.dart';
4+
5+
abstract class AppState extends Equatable {
6+
@override
7+
List<Object> get props => [];
8+
}
9+
10+
class AppError extends AppState {}
11+
12+
class AppEmpty extends AppState {}
13+
14+
class AppLoading extends AppState {}
15+
16+
class AppLoaded extends AppState {
17+
final MoviesResponse response;
18+
19+
AppLoaded({@required this.response});
20+
}

lib/src/blocs/blocs.dart

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export 'app_bloc.dart';
2+
export 'app_event.dart';
3+
export 'app_state.dart';

lib/src/models/models.dart

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export 'movies.dart';

0 commit comments

Comments
 (0)