From 74bb1123d671f3257ebd49681c3884b4f3f9a6f6 Mon Sep 17 00:00:00 2001 From: nkhanh44 Date: Wed, 23 Aug 2023 01:13:50 +0700 Subject: [PATCH] [#31] Add unit test --- lib/di/interceptor/app_interceptor.dart | 16 +--- lib/main.dart | 2 +- lib/model/survey_model.dart | 8 ++ lib/repositories/survey_repository.dart | 6 +- lib/screens/home/home_screen.dart | 30 ++++--- lib/screens/home/home_view_model.dart | 2 +- lib/usecases/get_cached_surveys_use_case.dart | 2 +- .../repositories/survey_repository_test.dart | 2 +- .../get_cached_surveys_use_case_test.dart | 32 ++++++++ .../usecases/get_surveys_user_case_test.dart | 13 ++- test/mocks/generate_mocks.dart | 2 +- test/screens/home/home_view_model_test.dart | 82 +++++++++++++++++++ 12 files changed, 150 insertions(+), 47 deletions(-) create mode 100644 test/api/usecases/get_cached_surveys_use_case_test.dart create mode 100644 test/screens/home/home_view_model_test.dart diff --git a/lib/di/interceptor/app_interceptor.dart b/lib/di/interceptor/app_interceptor.dart index b8241e7..1d923fd 100644 --- a/lib/di/interceptor/app_interceptor.dart +++ b/lib/di/interceptor/app_interceptor.dart @@ -17,19 +17,9 @@ class AppInterceptor extends Interceptor { Future onRequest( RequestOptions options, RequestInterceptorHandler handler) async { if (_requireAuthenticate) { - final apiTokenModel = - await _secureStorage?.getValue(key: SecureStorageKey.apiToken); - if (apiTokenModel is ApiToken) { - final accessToken = apiTokenModel.accessToken; - final tokenType = apiTokenModel.tokenType; - - - if (accessToken.isNotEmpty && tokenType.isNotEmpty) { - final authorizationHeader = '$tokenType $accessToken'; - options.headers - .putIfAbsent(_headerAuthorization, () => authorizationHeader); - } - } + // TODO header authorization here + // options.headers + // .putIfAbsent(HEADER_AUTHORIZATION, () => ""); } return super.onRequest(options, handler); } diff --git a/lib/main.dart b/lib/main.dart index 6cd7baf..8ddf2fc 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,7 +7,7 @@ import 'package:survey_flutter/screens/home/home_screen.dart'; import 'package:survey_flutter/screens/login/login_screen.dart'; import 'package:survey_flutter/screens/splash/splash_screen.dart'; import 'package:survey_flutter/theme/app_theme.dart'; -import 'package:survey_flutter/api/storage/survey_storage.dart'; +import 'package:survey_flutter/storage/survey_storage.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); diff --git a/lib/model/survey_model.dart b/lib/model/survey_model.dart index 82ee350..b5ffc92 100644 --- a/lib/model/survey_model.dart +++ b/lib/model/survey_model.dart @@ -38,4 +38,12 @@ class SurveyModel extends Equatable { description: description, coverImageUrl: coverImageUrl, ); + + const SurveyModel.dummy() + : this( + id: "id", + title: "title", + description: "description", + coverImageUrl: "coverImageUrl", + ); } diff --git a/lib/repositories/survey_repository.dart b/lib/repositories/survey_repository.dart index 40e57f9..6086727 100644 --- a/lib/repositories/survey_repository.dart +++ b/lib/repositories/survey_repository.dart @@ -1,12 +1,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:survey_flutter/api/exception/network_exceptions.dart'; -import 'package:survey_flutter/api/storage/survey_storage.dart'; +import 'package:survey_flutter/storage/survey_storage.dart'; import 'package:survey_flutter/api/survey_api_service.dart'; -import 'package:survey_flutter/di/provider/flutter_secure_storage.dart'; -import 'package:survey_flutter/model/response/survey_response.dart'; import 'package:survey_flutter/model/survey_model.dart'; -import 'package:survey_flutter/model/surveys_container_model.dart'; import 'package:survey_flutter/storage/secure_storage_impl.dart'; import '../di/provider/dio_provider.dart'; diff --git a/lib/screens/home/home_screen.dart b/lib/screens/home/home_screen.dart index 08c97f3..0481626 100644 --- a/lib/screens/home/home_screen.dart +++ b/lib/screens/home/home_screen.dart @@ -1,5 +1,3 @@ -import 'dart:ffi'; - import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:survey_flutter/model/survey_model.dart'; @@ -56,20 +54,20 @@ class _HomeScreenState extends ConsumerState { final errorMessage = ref.watch(_errorStreamProvider).value ?? ""; if (errorMessage.isNotEmpty) { - showAlertDialog( - context: context, - title: context.localizations.errorText, - message: errorMessage, - actions: [ - TextButton( - style: ButtonStyle( - foregroundColor: MaterialStateProperty.all(Colors.black), - ), - child: Text(context.localizations.okText), - onPressed: () => Navigator.pop(context), - ) - ], - ); + showAlertDialog( + context: context, + title: context.localizations.errorText, + message: errorMessage, + actions: [ + TextButton( + style: ButtonStyle( + foregroundColor: MaterialStateProperty.all(Colors.black), + ), + child: Text(context.localizations.okText), + onPressed: () => Navigator.pop(context), + ) + ], + ); } return Scaffold( body: Stack( diff --git a/lib/screens/home/home_view_model.dart b/lib/screens/home/home_view_model.dart index c357e32..830323e 100644 --- a/lib/screens/home/home_view_model.dart +++ b/lib/screens/home/home_view_model.dart @@ -53,7 +53,7 @@ class HomeViewModel extends StateNotifier { } } - void loadCachedSurveys() async { + void loadCachedSurveys() async { final result = await _getCachedSurveysUseCase.call(); if (result is Success>) { final cachedSurveys = diff --git a/lib/usecases/get_cached_surveys_use_case.dart b/lib/usecases/get_cached_surveys_use_case.dart index e7c25c1..0bc4b23 100644 --- a/lib/usecases/get_cached_surveys_use_case.dart +++ b/lib/usecases/get_cached_surveys_use_case.dart @@ -1,5 +1,5 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:survey_flutter/api/storage/survey_storage.dart'; +import 'package:survey_flutter/storage/survey_storage.dart'; import 'package:survey_flutter/model/survey_model.dart'; import 'package:survey_flutter/usecases/base/base_use_case.dart'; diff --git a/test/api/repositories/survey_repository_test.dart b/test/api/repositories/survey_repository_test.dart index 3d9f068..f57f9b5 100644 --- a/test/api/repositories/survey_repository_test.dart +++ b/test/api/repositories/survey_repository_test.dart @@ -31,7 +31,7 @@ void main() { final result = await surveyRepository.getSurveys(pageSize: 0, pageNumber: 0); - expect(result, surveysResponse.toSurveysContainerModel()); + expect(result, surveysResponse.toSurveysContainerModel().surveys); }); test('when getting surveys fails throws NetworkExceptions', () async { diff --git a/test/api/usecases/get_cached_surveys_use_case_test.dart b/test/api/usecases/get_cached_surveys_use_case_test.dart new file mode 100644 index 0000000..ffccb14 --- /dev/null +++ b/test/api/usecases/get_cached_surveys_use_case_test.dart @@ -0,0 +1,32 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:survey_flutter/model/survey_model.dart'; +import 'package:survey_flutter/usecases/base/base_use_case.dart'; +import 'package:survey_flutter/usecases/get_cached_surveys_use_case.dart'; + +import '../../mocks/generate_mocks.mocks.dart'; + +void main() { + group('GetCachedSurveysUseCaseTest', () { + late MockSurveyStorage mockSurveyStorage; + late GetCachedSurveysUseCase getCachedSurveysUseCase; + + setUp(() async { + mockSurveyStorage = MockSurveyStorage(); + getCachedSurveysUseCase = GetCachedSurveysUseCase(mockSurveyStorage); + }); + + test( + 'When fetching cached surveys returns cached surveys', + () async { + final surveys = []; + final successResult = Success>(surveys); + when(mockSurveyStorage.getSurveys()) + .thenAnswer((_) async => successResult.value); + final result = await getCachedSurveysUseCase.call(); + expect(result, isA>>()); + expect((result as Success>).value, surveys); + }, + ); + }); +} diff --git a/test/api/usecases/get_surveys_user_case_test.dart b/test/api/usecases/get_surveys_user_case_test.dart index bf680c8..e3e0260 100644 --- a/test/api/usecases/get_surveys_user_case_test.dart +++ b/test/api/usecases/get_surveys_user_case_test.dart @@ -1,5 +1,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; +import 'package:survey_flutter/model/survey_model.dart'; import 'package:survey_flutter/model/surveys_container_model.dart'; import 'package:survey_flutter/usecases/base/base_use_case.dart'; import 'package:survey_flutter/usecases/get_surveys_use_case.dart'; @@ -17,24 +18,20 @@ void main() { }); test('When getting surveys is successful returns Success ', () async { - final surveysContainerModel = SurveysContainerModel.dummy(); + final surveysModel = SurveysContainerModel.dummy().surveys; final surveysParams = SurveysParams(pageNumber: 0, pageSize: 10); when(mockRepository.getSurveys(pageNumber: 0, pageSize: 10)) - .thenAnswer((_) async => surveysContainerModel); - + .thenAnswer((_) async => surveysModel); final result = await getSurveysUseCase(surveysParams); - - expect(result, isA>()); + expect(result, isA>>()); }); test('returns Failed when getting surveys fails', () async { final surveysParams = SurveysParams(pageNumber: 0, pageSize: 10); - when(mockRepository.getSurveys(pageNumber: 0, pageSize: 10)) .thenThrow(Exception()); final result = await getSurveysUseCase(surveysParams); - - expect(result, isA>()); + expect(result, isA>>()); }); }); } diff --git a/test/mocks/generate_mocks.dart b/test/mocks/generate_mocks.dart index 4e1f64a..30611b9 100644 --- a/test/mocks/generate_mocks.dart +++ b/test/mocks/generate_mocks.dart @@ -1,7 +1,7 @@ import 'package:dio/dio.dart'; import 'package:mockito/annotations.dart'; import 'package:survey_flutter/api/authentication_api_service.dart'; -import 'package:survey_flutter/api/storage/survey_storage.dart'; +import 'package:survey_flutter/storage/survey_storage.dart'; import 'package:survey_flutter/api/survey_api_service.dart'; import 'package:survey_flutter/repositories/authentication_repository.dart'; import 'package:survey_flutter/storage/secure_storage.dart'; diff --git a/test/screens/home/home_view_model_test.dart b/test/screens/home/home_view_model_test.dart new file mode 100644 index 0000000..0cc4c36 --- /dev/null +++ b/test/screens/home/home_view_model_test.dart @@ -0,0 +1,82 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:survey_flutter/api/exception/network_exceptions.dart'; +import 'package:survey_flutter/model/survey_model.dart'; +import 'package:survey_flutter/screens/home/home_state.dart'; +import 'package:survey_flutter/screens/home/home_view_model.dart'; +import 'package:survey_flutter/usecases/base/base_use_case.dart'; +import 'package:survey_flutter/usecases/get_cached_surveys_use_case.dart'; +import 'package:survey_flutter/usecases/get_surveys_use_case.dart'; + +import '../../mocks/generate_mocks.mocks.dart'; // Import your generated mocks + +void main() { + group('HomeViewModel', () { + late MockGetCachedSurveysUseCase mockGetCachedSurveysUseCase; + late MockGetSurveysUseCase mockGetSurveysUseCase; + late HomeViewModel homeViewModel; + late ProviderContainer providerContainer; + + final List surveys = [ + const SurveyModel.dummy(), + const SurveyModel.dummy(), + ]; + + final UseCaseException exception = + UseCaseException(const NetworkExceptions.unauthorisedRequest()); + + setUp(() { + mockGetCachedSurveysUseCase = MockGetCachedSurveysUseCase(); + mockGetSurveysUseCase = MockGetSurveysUseCase(); + + providerContainer = ProviderContainer( + overrides: [ + getCachedSurveysUseCaseProvider + .overrideWithValue(mockGetCachedSurveysUseCase), + getSurveysUseCaseProvider.overrideWithValue(mockGetSurveysUseCase), + ], + ); + homeViewModel = providerContainer.read(homeViewModelProvider.notifier); + }); + + test('loads surveys successfully and emits LoadSurveysSuccess state', () async { + when(mockGetSurveysUseCase.call(any)).thenAnswer( + (_) async => Success(surveys), + ); + final surveysStream = homeViewModel.surveys; + homeViewModel.loadSurveys(); + expect(surveysStream, emitsInOrder([surveys])); + }, + ); + + test('loads cached surveys successfully and emits LoadCachedSurveysSuccess state', () async { + when(mockGetCachedSurveysUseCase.call()) + .thenAnswer((_) => Future.value(Success(surveys))); + final surveysStream = homeViewModel.surveys; + final stateStream = homeViewModel.stream; + homeViewModel.loadCachedSurveys(); + expect(surveysStream, emitsInOrder([surveys])); + expect(stateStream, + emitsInOrder([const HomeState.loadCachedSurveysSuccess()])); + }, + ); + + test('loads surveys with error and emits error state', () async { + when(mockGetSurveysUseCase.call(any)).thenAnswer( + (_) async => Failed(exception), + ); + final errorStream = homeViewModel.error; + homeViewModel.loadSurveys(); + expect( + errorStream, + emitsInOrder( + [NetworkExceptions.getErrorMessage(exception.actualException)], + ), + ); + }, + ); + + tearDown(() { providerContainer.dispose(); }); + }); +}