Skip to content

Commit

Permalink
[#31] Add unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
nkhanh44 committed Aug 22, 2023
1 parent 7f00b4d commit 74bb112
Show file tree
Hide file tree
Showing 12 changed files with 150 additions and 47 deletions.
16 changes: 3 additions & 13 deletions lib/di/interceptor/app_interceptor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
8 changes: 8 additions & 0 deletions lib/model/survey_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,12 @@ class SurveyModel extends Equatable {
description: description,
coverImageUrl: coverImageUrl,
);

const SurveyModel.dummy()
: this(
id: "id",
title: "title",
description: "description",
coverImageUrl: "coverImageUrl",
);
}
6 changes: 1 addition & 5 deletions lib/repositories/survey_repository.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand Down
30 changes: 14 additions & 16 deletions lib/screens/home/home_screen.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -56,20 +54,20 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
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(
Expand Down
2 changes: 1 addition & 1 deletion lib/screens/home/home_view_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class HomeViewModel extends StateNotifier<HomeState> {
}
}

void loadCachedSurveys() async {
void loadCachedSurveys() async {
final result = await _getCachedSurveysUseCase.call();
if (result is Success<List<SurveyModel>>) {
final cachedSurveys =
Expand Down
2 changes: 1 addition & 1 deletion lib/usecases/get_cached_surveys_use_case.dart
Original file line number Diff line number Diff line change
@@ -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';

Expand Down
2 changes: 1 addition & 1 deletion test/api/repositories/survey_repository_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
32 changes: 32 additions & 0 deletions test/api/usecases/get_cached_surveys_use_case_test.dart
Original file line number Diff line number Diff line change
@@ -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 = <SurveyModel>[];
final successResult = Success<List<SurveyModel>>(surveys);
when(mockSurveyStorage.getSurveys())
.thenAnswer((_) async => successResult.value);
final result = await getCachedSurveysUseCase.call();
expect(result, isA<Success<List<SurveyModel>>>());
expect((result as Success<List<SurveyModel>>).value, surveys);
},
);
});
}
13 changes: 5 additions & 8 deletions test/api/usecases/get_surveys_user_case_test.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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<Success<SurveysContainerModel>>());
expect(result, isA<Success<List<SurveyModel>>>());
});

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<Failed<SurveysContainerModel>>());
expect(result, isA<Failed<List<SurveyModel>>>());
});
});
}
2 changes: 1 addition & 1 deletion test/mocks/generate_mocks.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand Down
82 changes: 82 additions & 0 deletions test/screens/home/home_view_model_test.dart
Original file line number Diff line number Diff line change
@@ -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<SurveyModel> surveys = <SurveyModel>[
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(); });
});
}

0 comments on commit 74bb112

Please sign in to comment.