From 5ab98d24a012e38a3faca6f6e300ada7c1b2397d Mon Sep 17 00:00:00 2001 From: bwnyasse Date: Tue, 9 Nov 2021 15:24:09 -0500 Subject: [PATCH 01/13] step-1-TODO --- integration_test/app_test.dart | 45 ---------- integration_test/driver.dart | 3 - integration_test/main.dart | 20 ----- test/src/app_test.dart | 26 ------ test/src/blocs/app_bloc_test.dart | 63 -------------- test/src/blocs/app_bloc_test.mocks.dart | 45 ---------- test/src/models/movies_test.dart | 17 ---- test/src/services/app_service_test.dart | 36 +------- test/src/widgets/home_test.dart | 107 ------------------------ test/src/widgets/movie_card_test.dart | 44 ---------- test/src/widgets/movies_list_test.dart | 39 --------- 11 files changed, 4 insertions(+), 441 deletions(-) delete mode 100644 integration_test/app_test.dart delete mode 100644 integration_test/driver.dart delete mode 100644 integration_test/main.dart delete mode 100644 test/src/app_test.dart delete mode 100644 test/src/blocs/app_bloc_test.dart delete mode 100644 test/src/blocs/app_bloc_test.mocks.dart delete mode 100644 test/src/models/movies_test.dart delete mode 100644 test/src/widgets/home_test.dart delete mode 100644 test/src/widgets/movie_card_test.dart delete mode 100644 test/src/widgets/movies_list_test.dart diff --git a/integration_test/app_test.dart b/integration_test/app_test.dart deleted file mode 100644 index aa2495a..0000000 --- a/integration_test/app_test.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:integration_test/integration_test.dart'; -import 'main.dart' as app; - -void main() { - group('Testing App Performance Tests', () { - final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding; - - binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive; - - testWidgets('starts with topRated', (tester) async { - app.main(); - await tester.pumpAndSettle(); - - // Movie 1 - final titleTextFinder1 = find.byKey(Key('1-title')); - final overviewTextFinder1 = find.byKey(Key('1-overview')); - final releaseTextFinder1 = find.byKey(Key('1-releaseDate')); - // checking widget present or not - expect(titleTextFinder1, findsOneWidget); - expect(overviewTextFinder1, findsOneWidget); - expect(releaseTextFinder1, findsOneWidget); - - // checking values - expect((titleTextFinder1.evaluate().single.widget as Text).data, 'Fight Club'); - expect((overviewTextFinder1.evaluate().single.widget as Text).data, 'Overview 1'); - expect((releaseTextFinder1.evaluate().single.widget as Text).data, '1999-10-12'); - - // Movie 2 - final titleTextFinder2 = find.byKey(Key('2-title')); - final overviewTextFinder2 = find.byKey(Key('2-overview')); - final releaseTextFinder2 = find.byKey(Key('2-releaseDate')); - // checking widget present or not - expect(titleTextFinder2, findsOneWidget); - expect(overviewTextFinder2, findsOneWidget); - expect(releaseTextFinder2, findsOneWidget); - - // checking values - expect((titleTextFinder2.evaluate().single.widget as Text).data, 'Fight Club 2'); - expect((overviewTextFinder2.evaluate().single.widget as Text).data, 'Overview 2'); - expect((releaseTextFinder2.evaluate().single.widget as Text).data, '1999-10-20'); - }); - }); -} diff --git a/integration_test/driver.dart b/integration_test/driver.dart deleted file mode 100644 index b38629c..0000000 --- a/integration_test/driver.dart +++ /dev/null @@ -1,3 +0,0 @@ -import 'package:integration_test/integration_test_driver.dart'; - -Future main() => integrationDriver(); diff --git a/integration_test/main.dart b/integration_test/main.dart deleted file mode 100644 index eb410ec..0000000 --- a/integration_test/main.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:flutter_movie_deep_dive_test/src/app.dart'; -import 'package:flutter_movie_deep_dive_test/src/providers/providers.dart'; -import 'package:http/http.dart'; -import 'package:http/testing.dart'; - -import '../test/src/common.dart'; - -void main() { - final mockClient = MockClient((request) async { - return Response(json.encode(exampleJsonResponse2), 200); - }); - - return runApp(AppProvider( - httpClient: mockClient, - child: MyApp(), - )); -} diff --git a/test/src/app_test.dart b/test/src/app_test.dart deleted file mode 100644 index d684a19..0000000 --- a/test/src/app_test.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter_test/flutter_test.dart'; -import 'package:integration_test/integration_test.dart'; -import 'package:http/http.dart'; -import 'package:http/testing.dart'; -import 'package:flutter_movie_deep_dive_test/src/providers/providers.dart'; -import 'package:flutter_movie_deep_dive_test/src/widgets/widgets.dart'; -import 'package:flutter_movie_deep_dive_test/src/app.dart'; - -import 'common.dart'; - -void main() { - - testWidgets('Display App', (WidgetTester tester) async { - await tester.pumpWidget(AppProvider( - httpClient: MockClient((request) async { - return Response(json.encode(exampleJsonResponse), 200); - }), - child: MyApp(), - )); - - Finder textFinder = find.byType(MyHomePage); - expect(textFinder, findsOneWidget); - }); -} diff --git a/test/src/blocs/app_bloc_test.dart b/test/src/blocs/app_bloc_test.dart deleted file mode 100644 index f20483a..0000000 --- a/test/src/blocs/app_bloc_test.dart +++ /dev/null @@ -1,63 +0,0 @@ -import 'package:bloc_test/bloc_test.dart'; -import 'package:flutter_movie_deep_dive_test/src/blocs/blocs.dart'; -import 'package:flutter_movie_deep_dive_test/src/models/models.dart'; -import 'package:flutter_movie_deep_dive_test/src/services/services.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; -import 'package:mockito/annotations.dart'; - -import '../common.dart'; -import 'app_bloc_test.mocks.dart'; - -const loading = TypeMatcher(); -const error = TypeMatcher(); -const empty = TypeMatcher(); - -@GenerateMocks([AppService]) -main() { - MockAppService serviceMock = MockAppService(); - AppBloc appBloc = AppBloc(service: serviceMock, initWithState: AppEmpty()); - late MoviesResponse response; - - setUp(() { - response = MoviesResponse.fromJson(exampleJsonResponse); - }); - - tearDown(() { - appBloc.close(); - }); - - test('App close does not emit new app state', () async { - appBloc.close(); - await expectLater( - appBloc.stream, - emitsInOrder([emitsDone]), - ); - }); - - test('AppEmpty is initialState', () { - expect(appBloc.initWithState, empty); - }); - - group('Bloc AppState', () { - blocTest( - 'emits [AppError] state', - build: () { - when(serviceMock.loadMovies()).thenThrow(Error); - return AppBloc(service: serviceMock, initWithState: AppEmpty()); - }, - act: (bloc) => bloc.add(FetchEvent()), - expect: () => [empty, loading, error], - ); - - blocTest( - 'emits [AppLoaded] state', - build: () { - when(serviceMock.loadMovies()).thenAnswer((_) => Future.value(response)); - return AppBloc(service: serviceMock, initWithState: AppEmpty()); - }, - act: (bloc) => bloc.add(FetchEvent()), - expect: () => [empty, loading, AppLoaded(response: response)], - ); - }); -} diff --git a/test/src/blocs/app_bloc_test.mocks.dart b/test/src/blocs/app_bloc_test.mocks.dart deleted file mode 100644 index 6474203..0000000 --- a/test/src/blocs/app_bloc_test.mocks.dart +++ /dev/null @@ -1,45 +0,0 @@ -// Mocks generated by Mockito 5.0.16 from annotations -// in flutter_movie_deep_dive_test/test/src/blocs/app_bloc_test.dart. -// Do not manually edit this file. - -import 'dart:async' as _i5; - -import 'package:flutter_movie_deep_dive_test/src/models/models.dart' as _i3; -import 'package:flutter_movie_deep_dive_test/src/services/app_service.dart' - as _i4; -import 'package:http/http.dart' as _i2; -import 'package:mockito/mockito.dart' as _i1; - -// ignore_for_file: avoid_redundant_argument_values -// ignore_for_file: avoid_setters_without_getters -// ignore_for_file: comment_references -// ignore_for_file: implementation_imports -// ignore_for_file: invalid_use_of_visible_for_testing_member -// ignore_for_file: prefer_const_constructors -// ignore_for_file: unnecessary_parenthesis -// ignore_for_file: camel_case_types - -class _FakeClient_0 extends _i1.Fake implements _i2.Client {} - -class _FakeMoviesResponse_1 extends _i1.Fake implements _i3.MoviesResponse {} - -/// A class which mocks [AppService]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockAppService extends _i1.Mock implements _i4.AppService { - MockAppService() { - _i1.throwOnMissingStub(this); - } - - @override - _i2.Client get client => (super.noSuchMethod(Invocation.getter(#client), - returnValue: _FakeClient_0()) as _i2.Client); - @override - _i5.Future<_i3.MoviesResponse> loadMovies() => - (super.noSuchMethod(Invocation.method(#loadMovies, []), - returnValue: - Future<_i3.MoviesResponse>.value(_FakeMoviesResponse_1())) - as _i5.Future<_i3.MoviesResponse>); - @override - String toString() => super.toString(); -} diff --git a/test/src/models/movies_test.dart b/test/src/models/movies_test.dart deleted file mode 100644 index da523cd..0000000 --- a/test/src/models/movies_test.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:flutter_movie_deep_dive_test/src/models/models.dart'; -import 'package:flutter_test/flutter_test.dart'; - -main() { - group('movie.posterPathResolved', () { - test('posterPath is not empty', () { - Movie m = Movie(); - expect(m.posterPathResolved, equals('https://via.placeholder.com/300')); - }); - - test('posterPath is valid', () { - Movie m = Movie(posterPath: 'some-value'); - expect(m.posterPathResolved, - equals('http://image.tmdb.org/t/p/w185/some-value')); - }); - }); -} \ No newline at end of file diff --git a/test/src/services/app_service_test.dart b/test/src/services/app_service_test.dart index d148d79..c5daf57 100644 --- a/test/src/services/app_service_test.dart +++ b/test/src/services/app_service_test.dart @@ -1,36 +1,8 @@ -import 'dart:convert'; - -import 'package:flutter_movie_deep_dive_test/src/models/models.dart'; -import 'package:flutter_movie_deep_dive_test/src/services/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:http/http.dart'; -import 'package:http/testing.dart'; - -import '../common.dart'; main() { - group('loadMovies', () { - test('status == 200', () async { - final mockClient = MockClient((request) async { - return Response(json.encode(exampleJsonResponse), 200); - }); - final service = AppService(mockClient); - final expectedResponse = MoviesResponse.fromJson(exampleJsonResponse); - final actualResponse = await service.loadMovies(); - expect(actualResponse, equals(expectedResponse)); - }); - - test('status != 200', () async { - final mockClient = MockClient((request) async { - return Response(json.encode(exampleJsonResponse), 500); - }); - final service = AppService(mockClient); - expect( - () async => await service.loadMovies(), - throwsA(predicate((e) => - e is LoadMoviesException && - e.message == 'LoadMovies - Request Error: 500')), - ); - }); + test('loadMovies', () async { + // TODO 1- Must implement app_service#loadMovies + throw UnimplementedError(); }); -} \ No newline at end of file +} diff --git a/test/src/widgets/home_test.dart b/test/src/widgets/home_test.dart deleted file mode 100644 index f9e693d..0000000 --- a/test/src/widgets/home_test.dart +++ /dev/null @@ -1,107 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_movie_deep_dive_test/src/blocs/blocs.dart'; -import 'package:flutter_movie_deep_dive_test/src/models/models.dart'; -import 'package:flutter_movie_deep_dive_test/src/providers/providers.dart'; -import 'package:flutter_movie_deep_dive_test/src/services/services.dart'; -import 'package:flutter_movie_deep_dive_test/src/widgets/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:http/http.dart'; -import 'package:mockito/annotations.dart'; -import 'package:network_image_mock/network_image_mock.dart'; -import 'package:mockito/mockito.dart'; - -import '../blocs/app_bloc_test.mocks.dart'; -import '../common.dart'; - -class UnknowState extends AppState {} - -@GenerateMocks([AppService]) -void main() { - MockAppService serviceMock = MockAppService(); - late MoviesResponse response; - setUp(() { - response = MoviesResponse.fromJson(exampleJsonResponse2); - when(serviceMock.loadMovies()).thenAnswer((_) => Future.value(response)); - }); - - group('Display Home', () { - testWidgets('state: AppLoading', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: AppProvider( - httpClient: Client(), - child: BlocProvider( - create: (context) => AppBloc(service: serviceMock, initWithState: AppLoading()), - child: MyHomePage(title: 'Test Widget'), - ), - ), - ), - ), - ); - - Finder textFinder = find.byType(CircularProgressIndicator); - expect(textFinder, findsOneWidget); - }); - - testWidgets('state: AppLoaded', (WidgetTester tester) async { - mockNetworkImagesFor(() async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: AppProvider( - httpClient: Client(), - child: BlocProvider( - create: (context) => AppBloc(service: serviceMock, initWithState: AppLoaded(response: response)), - child: MyHomePage(title: 'Test Widget'), - ), - ), - ), - ), - ); - - Finder textFinder = find.byType(MoviesList); - expect(textFinder, findsOneWidget); - }); - }); - - testWidgets('state: AppError', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: AppProvider( - httpClient: Client(), - child: BlocProvider( - create: (context) => AppBloc(service: serviceMock, initWithState: AppError()), - child: MyHomePage(title: 'Test Widget'), - ), - ), - ), - ), - ); - - Finder textFinder = find.text('Something went wrong!'); - expect(textFinder, findsOneWidget); - }); - - testWidgets('state: unknow', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: AppProvider( - httpClient: Client(), - child: BlocProvider( - create: (context) => AppBloc(service: serviceMock, initWithState: UnknowState()), - child: MyHomePage(title: 'Test Widget'), - ), - ), - ), - ), - ); - - Finder textFinder = find.text('Wait ...'); - expect(textFinder, findsOneWidget); - }); - }); -} diff --git a/test/src/widgets/movie_card_test.dart b/test/src/widgets/movie_card_test.dart deleted file mode 100644 index 53aff79..0000000 --- a/test/src/widgets/movie_card_test.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_movie_deep_dive_test/src/models/models.dart'; -import 'package:flutter_movie_deep_dive_test/src/widgets/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:network_image_mock/network_image_mock.dart'; - -import '../common.dart'; - -void main() { - MoviesResponse exampleResponse; - late Movie movie; - - setUp(() { - exampleResponse = MoviesResponse.fromJson(exampleJsonResponse); - movie = exampleResponse.movies.first; - }); - - testWidgets('Display Movie Card', (WidgetTester tester) async { - mockNetworkImagesFor(() async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: MovieCard( - key: Key("${movie.id}"), - data: movie, - ), - ), - ), - ); - - final movieFinder = find.byType(MovieCard); - expect(movieFinder, findsOneWidget); - - Finder textFinder = find.text(movie.title ?? ""); - expect(textFinder, findsOneWidget); - - textFinder = find.text(movie.overview ?? ""); - expect(textFinder, findsOneWidget); - - textFinder = find.text(movie.releaseDate ?? ""); - expect(textFinder, findsOneWidget); - }); - }); -} diff --git a/test/src/widgets/movies_list_test.dart b/test/src/widgets/movies_list_test.dart deleted file mode 100644 index e647fa0..0000000 --- a/test/src/widgets/movies_list_test.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_movie_deep_dive_test/src/models/models.dart'; -import 'package:flutter_movie_deep_dive_test/src/widgets/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:network_image_mock/network_image_mock.dart'; - -import '../common.dart'; - -void main() { - late MoviesResponse exampleResponse; - - setUp(() { - exampleResponse = MoviesResponse.fromJson(exampleJsonResponse2); - }); - - testWidgets('Display Movies List', (WidgetTester tester) async { - mockNetworkImagesFor(() async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: MoviesList( - response: exampleResponse, - ), - ), - ), - ); - - Finder movieFinder = find.byType(MovieCard); - expect(movieFinder, findsNWidgets(2)); - - // Expect movie card from exampleJson - movieFinder = find.byKey(Key("1")); - expect(movieFinder, findsOneWidget); - - movieFinder = find.byKey(Key("2")); - expect(movieFinder, findsOneWidget); - }); - }); -} \ No newline at end of file From 4768c0a3fd2cbbd5b043d19d670d951fb9d21f20 Mon Sep 17 00:00:00 2001 From: bwnyasse Date: Tue, 9 Nov 2021 15:24:51 -0500 Subject: [PATCH 02/13] step-1 --- test/src/services/app_service_test.dart | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/test/src/services/app_service_test.dart b/test/src/services/app_service_test.dart index c5daf57..b19197d 100644 --- a/test/src/services/app_service_test.dart +++ b/test/src/services/app_service_test.dart @@ -1,8 +1,22 @@ +import 'dart:convert'; + +import 'package:flutter_movie_deep_dive_test/src/models/models.dart'; +import 'package:flutter_movie_deep_dive_test/src/services/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:http/http.dart'; +import 'package:http/testing.dart'; + +import '../common.dart'; main() { test('loadMovies', () async { - // TODO 1- Must implement app_service#loadMovies - throw UnimplementedError(); + // RESOLVE 1- Must implement app_service#loadMovies + final mockClient = MockClient((request) async { + return Response(json.encode(exampleJsonResponse), 200); + }); + final service = AppService(mockClient); + final expectedResponse = MoviesResponse.fromJson(exampleJsonResponse); + final actualResponse = await service.loadMovies(); + expect(actualResponse, equals(expectedResponse)); }); } From 0dba926423d67e8cc1ff30270fb9af1e9545af7e Mon Sep 17 00:00:00 2001 From: bwnyasse Date: Tue, 9 Nov 2021 15:30:42 -0500 Subject: [PATCH 03/13] step-2-TODO --- test/src/services/app_service_test.dart | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/test/src/services/app_service_test.dart b/test/src/services/app_service_test.dart index b19197d..5ad4963 100644 --- a/test/src/services/app_service_test.dart +++ b/test/src/services/app_service_test.dart @@ -9,14 +9,17 @@ import 'package:http/testing.dart'; import '../common.dart'; main() { - test('loadMovies', () async { - // RESOLVE 1- Must implement app_service#loadMovies - final mockClient = MockClient((request) async { - return Response(json.encode(exampleJsonResponse), 200); + group('loadMovies', () { + test('status == 200', () async { + final mockClient = MockClient((request) async { + return Response(json.encode(exampleJsonResponse), 200); + }); + final service = AppService(mockClient); + final expectedResponse = MoviesResponse.fromJson(exampleJsonResponse); + final actualResponse = await service.loadMovies(); + expect(actualResponse, equals(expectedResponse)); }); - final service = AppService(mockClient); - final expectedResponse = MoviesResponse.fromJson(exampleJsonResponse); - final actualResponse = await service.loadMovies(); - expect(actualResponse, equals(expectedResponse)); + + //TODO 1- Must test the case status != 200 }); } From e0fb8b794096f1bd7777aa52e685ddfce0d3eee4 Mon Sep 17 00:00:00 2001 From: bwnyasse Date: Tue, 9 Nov 2021 15:32:52 -0500 Subject: [PATCH 04/13] step-2 --- test/src/services/app_service_test.dart | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/src/services/app_service_test.dart b/test/src/services/app_service_test.dart index 5ad4963..18adeb8 100644 --- a/test/src/services/app_service_test.dart +++ b/test/src/services/app_service_test.dart @@ -20,6 +20,17 @@ main() { expect(actualResponse, equals(expectedResponse)); }); - //TODO 1- Must test the case status != 200 + test('status != 200', () async { + final mockClient = MockClient((request) async { + return Response(json.encode(exampleJsonResponse), 500); + }); + final service = AppService(mockClient); + expect( + () async => await service.loadMovies(), + throwsA(predicate( + (e) => e is LoadMoviesException && e.message == 'LoadMovies - Request Error: 500', + )), + ); + }); }); } From 9044507fc59a8c3a8d1135284b81cb7b32bfaf48 Mon Sep 17 00:00:00 2001 From: bwnyasse Date: Tue, 9 Nov 2021 15:36:22 -0500 Subject: [PATCH 05/13] step-3-TODO --- test/src/models/movies_test.dart | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 test/src/models/movies_test.dart diff --git a/test/src/models/movies_test.dart b/test/src/models/movies_test.dart new file mode 100644 index 0000000..b87869d --- /dev/null +++ b/test/src/models/movies_test.dart @@ -0,0 +1,10 @@ +import 'package:flutter_movie_deep_dive_test/src/models/models.dart'; +import 'package:flutter_test/flutter_test.dart'; + +main() { + group('movie.posterPathResolved', () { + test('posterPath is not empty', () { + //TODO 1- Test the case movie.posterPathResolved is null + }); + }); +} From d26419bd6887487ead77063cb7683bef7148ee5d Mon Sep 17 00:00:00 2001 From: bwnyasse Date: Tue, 9 Nov 2021 15:40:25 -0500 Subject: [PATCH 06/13] step-3 --- test/src/models/movies_test.dart | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/src/models/movies_test.dart b/test/src/models/movies_test.dart index b87869d..da523cd 100644 --- a/test/src/models/movies_test.dart +++ b/test/src/models/movies_test.dart @@ -4,7 +4,14 @@ import 'package:flutter_test/flutter_test.dart'; main() { group('movie.posterPathResolved', () { test('posterPath is not empty', () { - //TODO 1- Test the case movie.posterPathResolved is null + Movie m = Movie(); + expect(m.posterPathResolved, equals('https://via.placeholder.com/300')); + }); + + test('posterPath is valid', () { + Movie m = Movie(posterPath: 'some-value'); + expect(m.posterPathResolved, + equals('http://image.tmdb.org/t/p/w185/some-value')); }); }); -} +} \ No newline at end of file From ed1e59af21c631764069aac6849bfbd82dbfd824 Mon Sep 17 00:00:00 2001 From: bwnyasse Date: Tue, 9 Nov 2021 15:45:28 -0500 Subject: [PATCH 07/13] step-4-TODO --- test/src/blocs/app_bloc_test.dart | 38 +++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 test/src/blocs/app_bloc_test.dart diff --git a/test/src/blocs/app_bloc_test.dart b/test/src/blocs/app_bloc_test.dart new file mode 100644 index 0000000..dfa93ff --- /dev/null +++ b/test/src/blocs/app_bloc_test.dart @@ -0,0 +1,38 @@ +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter_movie_deep_dive_test/src/blocs/blocs.dart'; +import 'package:flutter_movie_deep_dive_test/src/models/models.dart'; +import 'package:flutter_movie_deep_dive_test/src/services/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; + +import '../common.dart'; +import 'app_bloc_test.mocks.dart'; + +const loading = TypeMatcher(); +const error = TypeMatcher(); +const empty = TypeMatcher(); + +@GenerateMocks([AppService]) +main() { + MockAppService serviceMock = MockAppService(); + AppBloc appBloc = AppBloc(service: serviceMock, initWithState: AppEmpty()); + late MoviesResponse response; + + setUp(() { + response = MoviesResponse.fromJson(exampleJsonResponse); + }); + + tearDown(() { + appBloc.close(); + }); + + test('App close does not emit new app state', () async { + appBloc.close(); + //TODO: 1- Must implement and check emitsDone + throw UnimplementedError(); + }); + + test('AppEmpty is initialState', () { + expect(appBloc.initWithState, empty); + }); +} From 3d2167ce9e7c17e479122172e72025f9c2360a6f Mon Sep 17 00:00:00 2001 From: bwnyasse Date: Tue, 9 Nov 2021 15:47:07 -0500 Subject: [PATCH 08/13] step-4 --- test/src/blocs/app_bloc_test.dart | 31 +++++++++++++++-- test/src/blocs/app_bloc_test.mocks.dart | 45 +++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 test/src/blocs/app_bloc_test.mocks.dart diff --git a/test/src/blocs/app_bloc_test.dart b/test/src/blocs/app_bloc_test.dart index dfa93ff..4cb623e 100644 --- a/test/src/blocs/app_bloc_test.dart +++ b/test/src/blocs/app_bloc_test.dart @@ -3,6 +3,7 @@ import 'package:flutter_movie_deep_dive_test/src/blocs/blocs.dart'; import 'package:flutter_movie_deep_dive_test/src/models/models.dart'; import 'package:flutter_movie_deep_dive_test/src/services/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; import 'package:mockito/annotations.dart'; import '../common.dart'; @@ -28,11 +29,35 @@ main() { test('App close does not emit new app state', () async { appBloc.close(); - //TODO: 1- Must implement and check emitsDone - throw UnimplementedError(); + await expectLater( + appBloc.stream, + emitsInOrder([emitsDone]), + ); }); test('AppEmpty is initialState', () { expect(appBloc.initWithState, empty); }); -} + + group('Bloc AppState', () { + blocTest( + 'emits [AppError] state', + build: () { + when(serviceMock.loadMovies()).thenThrow(Error); + return AppBloc(service: serviceMock, initWithState: AppEmpty()); + }, + act: (bloc) => bloc.add(FetchEvent()), + expect: () => [empty, loading, error], + ); + + blocTest( + 'emits [AppLoaded] state', + build: () { + when(serviceMock.loadMovies()).thenAnswer((_) => Future.value(response)); + return AppBloc(service: serviceMock, initWithState: AppEmpty()); + }, + act: (bloc) => bloc.add(FetchEvent()), + expect: () => [empty, loading, AppLoaded(response: response)], + ); + }); +} \ No newline at end of file diff --git a/test/src/blocs/app_bloc_test.mocks.dart b/test/src/blocs/app_bloc_test.mocks.dart new file mode 100644 index 0000000..6474203 --- /dev/null +++ b/test/src/blocs/app_bloc_test.mocks.dart @@ -0,0 +1,45 @@ +// Mocks generated by Mockito 5.0.16 from annotations +// in flutter_movie_deep_dive_test/test/src/blocs/app_bloc_test.dart. +// Do not manually edit this file. + +import 'dart:async' as _i5; + +import 'package:flutter_movie_deep_dive_test/src/models/models.dart' as _i3; +import 'package:flutter_movie_deep_dive_test/src/services/app_service.dart' + as _i4; +import 'package:http/http.dart' as _i2; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types + +class _FakeClient_0 extends _i1.Fake implements _i2.Client {} + +class _FakeMoviesResponse_1 extends _i1.Fake implements _i3.MoviesResponse {} + +/// A class which mocks [AppService]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockAppService extends _i1.Mock implements _i4.AppService { + MockAppService() { + _i1.throwOnMissingStub(this); + } + + @override + _i2.Client get client => (super.noSuchMethod(Invocation.getter(#client), + returnValue: _FakeClient_0()) as _i2.Client); + @override + _i5.Future<_i3.MoviesResponse> loadMovies() => + (super.noSuchMethod(Invocation.method(#loadMovies, []), + returnValue: + Future<_i3.MoviesResponse>.value(_FakeMoviesResponse_1())) + as _i5.Future<_i3.MoviesResponse>); + @override + String toString() => super.toString(); +} From 38a30d8091528a47d18c60bc7cb9302c6f44b65e Mon Sep 17 00:00:00 2001 From: bwnyasse Date: Tue, 9 Nov 2021 15:52:26 -0500 Subject: [PATCH 09/13] step-5 --- test/src/app_test.dart | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 test/src/app_test.dart diff --git a/test/src/app_test.dart b/test/src/app_test.dart new file mode 100644 index 0000000..aaa8acc --- /dev/null +++ b/test/src/app_test.dart @@ -0,0 +1,24 @@ +import 'dart:convert'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:http/http.dart'; +import 'package:http/testing.dart'; +import 'package:flutter_movie_deep_dive_test/src/providers/providers.dart'; +import 'package:flutter_movie_deep_dive_test/src/widgets/widgets.dart'; +import 'package:flutter_movie_deep_dive_test/src/app.dart'; + +import 'common.dart'; + +void main() { + testWidgets('Display App', (WidgetTester tester) async { + await tester.pumpWidget(AppProvider( + httpClient: MockClient((request) async { + return Response(json.encode(exampleJsonResponse), 200); + }), + child: MyApp(), + )); + + Finder textFinder = find.byType(MyHomePage); + expect(textFinder, findsOneWidget); + }); +} From 648e815f9002b0ed330e28c0984fcb40e26cee01 Mon Sep 17 00:00:00 2001 From: bwnyasse Date: Tue, 9 Nov 2021 15:57:59 -0500 Subject: [PATCH 10/13] step6-TODO --- test/src/widgets/movie_card_test.dart | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 test/src/widgets/movie_card_test.dart diff --git a/test/src/widgets/movie_card_test.dart b/test/src/widgets/movie_card_test.dart new file mode 100644 index 0000000..3dd8f9b --- /dev/null +++ b/test/src/widgets/movie_card_test.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_movie_deep_dive_test/src/models/models.dart'; +import 'package:flutter_movie_deep_dive_test/src/widgets/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:network_image_mock/network_image_mock.dart'; + +import '../common.dart'; + +void main() { + MoviesResponse exampleResponse; + late Movie movie; + + setUp(() { + exampleResponse = MoviesResponse.fromJson(exampleJsonResponse); + movie = exampleResponse.movies.first; + }); + + testWidgets('Display Movie Card', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: MovieCard( + //TODO 1- Initialize the key with the movie.id + data: movie, + ), + ), + ), + ); + + //TODO: 2- Find objects to match + throw UnimplementedError(); + }); +} From 5fc0273b94720a42cefb9125b3b2c4035a4537b9 Mon Sep 17 00:00:00 2001 From: bwnyasse Date: Tue, 9 Nov 2021 16:08:29 -0500 Subject: [PATCH 11/13] step-6 --- test/src/widgets/movie_card_test.dart | 33 ++++++++++++++++++--------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/test/src/widgets/movie_card_test.dart b/test/src/widgets/movie_card_test.dart index 3dd8f9b..fe174cf 100644 --- a/test/src/widgets/movie_card_test.dart +++ b/test/src/widgets/movie_card_test.dart @@ -16,18 +16,29 @@ void main() { }); testWidgets('Display Movie Card', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: MovieCard( - //TODO 1- Initialize the key with the movie.id - data: movie, + mockNetworkImagesFor(() async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: MovieCard( + key: Key("${movie.id}"), + data: movie, + ), ), ), - ), - ); + ); - //TODO: 2- Find objects to match - throw UnimplementedError(); + final movieFinder = find.byType(MovieCard); + expect(movieFinder, findsOneWidget); + + Finder textFinder = find.text(movie.title ?? ""); + expect(textFinder, findsOneWidget); + + textFinder = find.text(movie.overview ?? ""); + expect(textFinder, findsOneWidget); + + textFinder = find.text(movie.releaseDate ?? ""); + expect(textFinder, findsOneWidget); + }); }); -} +} \ No newline at end of file From 56877f8660bdce428cd1cf43e3fa7ddaf16ab305 Mon Sep 17 00:00:00 2001 From: bwnyasse Date: Tue, 9 Nov 2021 16:13:38 -0500 Subject: [PATCH 12/13] step-7-TODO --- test/src/widgets/movies_list_test.dart | 41 ++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 test/src/widgets/movies_list_test.dart diff --git a/test/src/widgets/movies_list_test.dart b/test/src/widgets/movies_list_test.dart new file mode 100644 index 0000000..0c38bb3 --- /dev/null +++ b/test/src/widgets/movies_list_test.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_movie_deep_dive_test/src/models/models.dart'; +import 'package:flutter_movie_deep_dive_test/src/widgets/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:network_image_mock/network_image_mock.dart'; + +import '../common.dart'; + +void main() { + late MoviesResponse exampleResponse; + + setUp(() { + exampleResponse = MoviesResponse.fromJson(exampleJsonResponse2); + }); + + testWidgets('Display Movies List', (WidgetTester tester) async { + mockNetworkImagesFor(() async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: MoviesList( + response: exampleResponse, + ), + ), + ), + ); + + Finder movieFinder = find.byType(MovieCard); + //TODO 1- Fix this following except method + expect(movieFinder, findsNWidgets(1)); + + // Expect movie card from exampleJson + movieFinder = find.byKey(Key("1")); + expect(movieFinder, findsOneWidget); + + //TODO 2- Fix the following find.byKey + movieFinder = find.byKey(Key("4")); + expect(movieFinder, findsOneWidget); + }); + }); +} From 08598ddd3f26c2a1f32b13b25ffadadab617dffd Mon Sep 17 00:00:00 2001 From: bwnyasse Date: Tue, 9 Nov 2021 16:20:50 -0500 Subject: [PATCH 13/13] step-7 --- test/src/widgets/movies_list_test.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/src/widgets/movies_list_test.dart b/test/src/widgets/movies_list_test.dart index 0c38bb3..ab3619d 100644 --- a/test/src/widgets/movies_list_test.dart +++ b/test/src/widgets/movies_list_test.dart @@ -26,15 +26,13 @@ void main() { ); Finder movieFinder = find.byType(MovieCard); - //TODO 1- Fix this following except method - expect(movieFinder, findsNWidgets(1)); + expect(movieFinder, findsNWidgets(2)); // Expect movie card from exampleJson movieFinder = find.byKey(Key("1")); expect(movieFinder, findsOneWidget); - //TODO 2- Fix the following find.byKey - movieFinder = find.byKey(Key("4")); + movieFinder = find.byKey(Key("2")); expect(movieFinder, findsOneWidget); }); });