Skip to content

Commit

Permalink
chore: write tests for survey detail screen
Browse files Browse the repository at this point in the history
  • Loading branch information
markgravity committed May 14, 2021
1 parent 450df07 commit 7ec307c
Show file tree
Hide file tree
Showing 13 changed files with 594 additions and 55 deletions.
2 changes: 2 additions & 0 deletions lib/modules/survey_detail/components/content.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class Content extends StatelessWidget {
StreamsSelector0<SurveyInfo>.value(
stream: state._survey,
builder: (_, survey, __) => Image(
key: SurveyDetailView.backgroundImageKey,
image: NetworkImage(survey.coverImageUrl!),
fit: BoxFit.fill,
),
Expand Down Expand Up @@ -67,6 +68,7 @@ class Content extends StatelessWidget {
minWidth: 140,
),
child: Button(
key: SurveyDetailView.startSurveyButtonKey,
onPressed: () => state
.delegate?.startSurveyButtonDidTap
.add(null),
Expand Down
3 changes: 3 additions & 0 deletions lib/modules/survey_detail/survey_detail_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ abstract class SurveyDetailViewDelegate implements AlertViewMixinDelegate {

abstract class SurveyDetailView extends View<SurveyDetailViewDelegate>
with ProgressHUDViewMixin, AlertViewMixin {
static const backgroundImageKey = Key("background_image_");
static const startSurveyButtonKey = Key("start_survey_button");

void setSurvey(SurveyInfo survey);
}

Expand Down
70 changes: 40 additions & 30 deletions test/modules/home/home_interactor_test.mocks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
// in survey/test/modules/home/home_interactor_test.dart.
// Do not manually edit this file.

import 'dart:async' as _i7;
import 'dart:async' as _i8;

import 'package:mockito/mockito.dart' as _i1;
import 'package:rxdart/src/subjects/behavior_subject.dart' as _i2;
import 'package:survey/models/survey_info.dart' as _i4;
import 'package:survey/models/user_info.dart' as _i5;
import 'package:survey/modules/home/home_module.dart' as _i3;
import 'package:survey/repositories/auth_repository.dart' as _i8;
import 'package:survey/repositories/survey_repository.dart' as _i6;
import 'package:survey/models/detailed_survey_info.dart' as _i3;
import 'package:survey/models/survey_info.dart' as _i5;
import 'package:survey/models/user_info.dart' as _i6;
import 'package:survey/modules/home/home_module.dart' as _i4;
import 'package:survey/repositories/auth_repository.dart' as _i9;
import 'package:survey/repositories/survey_repository.dart' as _i7;

// ignore_for_file: comment_references
// ignore_for_file: unnecessary_parenthesis
Expand All @@ -22,11 +23,14 @@ import 'package:survey/repositories/survey_repository.dart' as _i6;
class _FakeBehaviorSubject<T> extends _i1.Fake
implements _i2.BehaviorSubject<T> {}

class _FakeDetailedSurveyInfo extends _i1.Fake
implements _i3.DetailedSurveyInfo {}

/// A class which mocks [HomeInteractorDelegate].
///
/// See the documentation for Mockito's code generation for more information.
class MockHomeInteractorDelegate extends _i1.Mock
implements _i3.HomeInteractorDelegate {
implements _i4.HomeInteractorDelegate {
MockHomeInteractorDelegate() {
_i1.throwOnMissingStub(this);
}
Expand All @@ -36,46 +40,52 @@ class MockHomeInteractorDelegate extends _i1.Mock
Invocation.getter(#isSurveysCachedDidGet),
returnValue: _FakeBehaviorSubject<bool>()) as _i2.BehaviorSubject<bool>);
@override
_i2.BehaviorSubject<List<_i4.SurveyInfo>> get surveysDidFetch =>
_i2.BehaviorSubject<List<_i5.SurveyInfo>> get surveysDidFetch =>
(super.noSuchMethod(Invocation.getter(#surveysDidFetch),
returnValue: _FakeBehaviorSubject<List<_i4.SurveyInfo>>())
as _i2.BehaviorSubject<List<_i4.SurveyInfo>>);
returnValue: _FakeBehaviorSubject<List<_i5.SurveyInfo>>())
as _i2.BehaviorSubject<List<_i5.SurveyInfo>>);
@override
_i2.BehaviorSubject<Exception> get surveysDidFailToFetch =>
(super.noSuchMethod(Invocation.getter(#surveysDidFailToFetch),
returnValue: _FakeBehaviorSubject<Exception>())
as _i2.BehaviorSubject<Exception>);
@override
_i2.BehaviorSubject<_i5.UserInfo> get authenticatedUserDidGet =>
_i2.BehaviorSubject<_i6.UserInfo> get authenticatedUserDidGet =>
(super.noSuchMethod(Invocation.getter(#authenticatedUserDidGet),
returnValue: _FakeBehaviorSubject<_i5.UserInfo>())
as _i2.BehaviorSubject<_i5.UserInfo>);
returnValue: _FakeBehaviorSubject<_i6.UserInfo>())
as _i2.BehaviorSubject<_i6.UserInfo>);
}

/// A class which mocks [SurveyRepository].
///
/// See the documentation for Mockito's code generation for more information.
class MockSurveyRepository extends _i1.Mock implements _i6.SurveyRepository {
class MockSurveyRepository extends _i1.Mock implements _i7.SurveyRepository {
MockSurveyRepository() {
_i1.throwOnMissingStub(this);
}

@override
_i7.Future<bool> get isSurveysCached =>
_i8.Future<bool> get isSurveysCached =>
(super.noSuchMethod(Invocation.getter(#isSurveysCached),
returnValue: Future<bool>.value(false)) as _i7.Future<bool>);
returnValue: Future<bool>.value(false)) as _i8.Future<bool>);
@override
_i7.Future<List<_i4.SurveyInfo>> fetchSurveys({bool? force}) =>
_i8.Future<List<_i5.SurveyInfo>> fetchSurveys({bool? force}) =>
(super.noSuchMethod(Invocation.method(#fetchSurveys, [], {#force: force}),
returnValue:
Future<List<_i4.SurveyInfo>>.value(<_i4.SurveyInfo>[]))
as _i7.Future<List<_i4.SurveyInfo>>);
Future<List<_i5.SurveyInfo>>.value(<_i5.SurveyInfo>[]))
as _i8.Future<List<_i5.SurveyInfo>>);
@override
_i8.Future<_i3.DetailedSurveyInfo> fetchDetailedSurvey(String? id) =>
(super.noSuchMethod(Invocation.method(#fetchDetailedSurvey, [id]),
returnValue: Future<_i3.DetailedSurveyInfo>.value(
_FakeDetailedSurveyInfo()))
as _i8.Future<_i3.DetailedSurveyInfo>);
}

/// A class which mocks [AuthRepository].
///
/// See the documentation for Mockito's code generation for more information.
class MockAuthRepository extends _i1.Mock implements _i8.AuthRepository {
class MockAuthRepository extends _i1.Mock implements _i9.AuthRepository {
MockAuthRepository() {
_i1.throwOnMissingStub(this);
}
Expand All @@ -85,29 +95,29 @@ class MockAuthRepository extends _i1.Mock implements _i8.AuthRepository {
.noSuchMethod(Invocation.getter(#isAuthenticated), returnValue: false)
as bool);
@override
_i7.Future<void> login({String? email, String? password}) =>
_i8.Future<void> login({String? email, String? password}) =>
(super.noSuchMethod(
Invocation.method(#login, [], {#email: email, #password: password}),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i7.Future<void>);
returnValueForMissingStub: Future.value()) as _i8.Future<void>);
@override
_i7.Future<void> logout() =>
_i8.Future<void> logout() =>
(super.noSuchMethod(Invocation.method(#logout, []),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i7.Future<void>);
returnValueForMissingStub: Future.value()) as _i8.Future<void>);
@override
_i7.Future<void> attempt() =>
_i8.Future<void> attempt() =>
(super.noSuchMethod(Invocation.method(#attempt, []),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i7.Future<void>);
returnValueForMissingStub: Future.value()) as _i8.Future<void>);
@override
_i7.Future<void> fetchUser() =>
_i8.Future<void> fetchUser() =>
(super.noSuchMethod(Invocation.method(#fetchUser, []),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i7.Future<void>);
returnValueForMissingStub: Future.value()) as _i8.Future<void>);
@override
_i7.Future<void> attemptAndFetchUser() =>
_i8.Future<void> attemptAndFetchUser() =>
(super.noSuchMethod(Invocation.method(#attemptAndFetchUser, []),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i7.Future<void>);
returnValueForMissingStub: Future.value()) as _i8.Future<void>);
}
3 changes: 1 addition & 2 deletions test/modules/home/home_router_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ void main() {
.thenReturn(navigatorState);
when(navigatorState.pushNamed(any, arguments: anyNamed("arguments")))
.thenAnswer((_) => Future.value());
router.pushToSurveyDetail(
context: buildContext, survey: SurveyInfo());
router.pushToSurveyDetail(context: buildContext, survey: SurveyInfo());
});

it("triggers navigator to push to Survey Detail screen", () {
Expand Down
56 changes: 33 additions & 23 deletions test/modules/side_menu/side_menu_interactor_test.mocks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
// in survey/test/modules/side_menu/side_menu_interactor_test.dart.
// Do not manually edit this file.

import 'dart:async' as _i5;
import 'dart:async' as _i6;

import 'package:mockito/mockito.dart' as _i1;
import 'package:rxdart/src/subjects/behavior_subject.dart' as _i2;
import 'package:survey/models/survey_info.dart' as _i6;
import 'package:survey/modules/side_menu/side_menu_module.dart' as _i3;
import 'package:survey/repositories/auth_repository.dart' as _i7;
import 'package:survey/repositories/survey_repository.dart' as _i4;
import 'package:survey/models/detailed_survey_info.dart' as _i3;
import 'package:survey/models/survey_info.dart' as _i7;
import 'package:survey/modules/side_menu/side_menu_module.dart' as _i4;
import 'package:survey/repositories/auth_repository.dart' as _i8;
import 'package:survey/repositories/survey_repository.dart' as _i5;

// ignore_for_file: comment_references
// ignore_for_file: unnecessary_parenthesis
Expand All @@ -21,11 +22,14 @@ import 'package:survey/repositories/survey_repository.dart' as _i4;
class _FakeBehaviorSubject<T> extends _i1.Fake
implements _i2.BehaviorSubject<T> {}

class _FakeDetailedSurveyInfo extends _i1.Fake
implements _i3.DetailedSurveyInfo {}

/// A class which mocks [SideMenuInteractorDelegate].
///
/// See the documentation for Mockito's code generation for more information.
class MockSideMenuInteractorDelegate extends _i1.Mock
implements _i3.SideMenuInteractorDelegate {
implements _i4.SideMenuInteractorDelegate {
MockSideMenuInteractorDelegate() {
_i1.throwOnMissingStub(this);
}
Expand All @@ -39,27 +43,33 @@ class MockSideMenuInteractorDelegate extends _i1.Mock
/// A class which mocks [SurveyRepository].
///
/// See the documentation for Mockito's code generation for more information.
class MockSurveyRepository extends _i1.Mock implements _i4.SurveyRepository {
class MockSurveyRepository extends _i1.Mock implements _i5.SurveyRepository {
MockSurveyRepository() {
_i1.throwOnMissingStub(this);
}

@override
_i5.Future<bool> get isSurveysCached =>
_i6.Future<bool> get isSurveysCached =>
(super.noSuchMethod(Invocation.getter(#isSurveysCached),
returnValue: Future<bool>.value(false)) as _i5.Future<bool>);
returnValue: Future<bool>.value(false)) as _i6.Future<bool>);
@override
_i5.Future<List<_i6.SurveyInfo>> fetchSurveys({bool? force}) =>
_i6.Future<List<_i7.SurveyInfo>> fetchSurveys({bool? force}) =>
(super.noSuchMethod(Invocation.method(#fetchSurveys, [], {#force: force}),
returnValue:
Future<List<_i6.SurveyInfo>>.value(<_i6.SurveyInfo>[]))
as _i5.Future<List<_i6.SurveyInfo>>);
Future<List<_i7.SurveyInfo>>.value(<_i7.SurveyInfo>[]))
as _i6.Future<List<_i7.SurveyInfo>>);
@override
_i6.Future<_i3.DetailedSurveyInfo> fetchDetailedSurvey(String? id) =>
(super.noSuchMethod(Invocation.method(#fetchDetailedSurvey, [id]),
returnValue: Future<_i3.DetailedSurveyInfo>.value(
_FakeDetailedSurveyInfo()))
as _i6.Future<_i3.DetailedSurveyInfo>);
}

/// A class which mocks [AuthRepository].
///
/// See the documentation for Mockito's code generation for more information.
class MockAuthRepository extends _i1.Mock implements _i7.AuthRepository {
class MockAuthRepository extends _i1.Mock implements _i8.AuthRepository {
MockAuthRepository() {
_i1.throwOnMissingStub(this);
}
Expand All @@ -69,29 +79,29 @@ class MockAuthRepository extends _i1.Mock implements _i7.AuthRepository {
.noSuchMethod(Invocation.getter(#isAuthenticated), returnValue: false)
as bool);
@override
_i5.Future<void> login({String? email, String? password}) =>
_i6.Future<void> login({String? email, String? password}) =>
(super.noSuchMethod(
Invocation.method(#login, [], {#email: email, #password: password}),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i5.Future<void>);
returnValueForMissingStub: Future.value()) as _i6.Future<void>);
@override
_i5.Future<void> logout() =>
_i6.Future<void> logout() =>
(super.noSuchMethod(Invocation.method(#logout, []),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i5.Future<void>);
returnValueForMissingStub: Future.value()) as _i6.Future<void>);
@override
_i5.Future<void> attempt() =>
_i6.Future<void> attempt() =>
(super.noSuchMethod(Invocation.method(#attempt, []),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i5.Future<void>);
returnValueForMissingStub: Future.value()) as _i6.Future<void>);
@override
_i5.Future<void> fetchUser() =>
_i6.Future<void> fetchUser() =>
(super.noSuchMethod(Invocation.method(#fetchUser, []),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i5.Future<void>);
returnValueForMissingStub: Future.value()) as _i6.Future<void>);
@override
_i5.Future<void> attemptAndFetchUser() =>
_i6.Future<void> attemptAndFetchUser() =>
(super.noSuchMethod(Invocation.method(#attemptAndFetchUser, []),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i5.Future<void>);
returnValueForMissingStub: Future.value()) as _i6.Future<void>);
}
77 changes: 77 additions & 0 deletions test/modules/survey_detail/survey_detail_interactor_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:quick_test/quick_test.dart';
import 'package:survey/models/detailed_survey_info.dart';
import 'package:survey/models/survey_info.dart';
import 'package:survey/modules/survey_detail/survey_detail_module.dart';
import 'package:survey/repositories/survey_repository.dart';
import 'package:survey/services/locator/locator_service.dart';
import '../../helpers/behavior_subject_generator.dart';
import 'survey_detail_interactor_test.mocks.dart';

@GenerateMocks([SurveyDetailInteractorDelegate, SurveyRepository])
void main() {
describe("a SurveyDetail interactor", () {
late SurveyDetailInteractor interactor;
late MockSurveyDetailInteractorDelegate delegate;
late BehaviorSubjectGenerator generator;
late MockSurveyRepository surveyRepository;

final survey = SurveyInfo();
survey.id = "id";

beforeEach(() {
generator = BehaviorSubjectGenerator();

surveyRepository = MockSurveyRepository();
locator.registerSingleton<SurveyRepository>(surveyRepository);

delegate = MockSurveyDetailInteractorDelegate();
when(delegate.detailedSurveyDidFetch)
.thenAnswer((realInvocation) => generator.make(0));
when(delegate.detailedSurveyDidFailToFetch)
.thenAnswer((realInvocation) => generator.make(1));

interactor = SurveyDetailInteractorImpl();
interactor.delegate = delegate;
interactor.arguments = SurveyDetailArguments(survey: survey);
});

describe("it's survey is got", () {
it("returns correct survey", () {
expect(interactor.survey, survey);
});
});

describe("it's fetchDetailedSurvey() is called", () {
context("when survey repository's fetchDetailedSurvey() return success",
() {
final detailedSurvey = DetailedSurveyInfo();
beforeEach(() {
when(surveyRepository.fetchDetailedSurvey(any))
.thenAnswer((realInvocation) => Future.value(detailedSurvey));
interactor.fetchDetailedSurvey();
});

it("triggers delegate's detailedSurveyDidFetch emits", () {
expect(delegate.detailedSurveyDidFetch, emits(detailedSurvey));
});
});

context("when survey repository's fetchDetailedSurvey() return failure",
() {
final exception = Exception();
beforeEach(() {
when(surveyRepository.fetchDetailedSurvey(any))
.thenAnswer((realInvocation) => Future.error(exception));
interactor.fetchDetailedSurvey();
});

it("triggers delegate's detailedSurveyDidFailToFetch emits", () {
expect(delegate.detailedSurveyDidFailToFetch, emits(exception));
});
});
});
});
}
Loading

0 comments on commit 7ec307c

Please sign in to comment.