-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
created the repository implementation in the data layer with test dri…
…ven development (news feed feature)
- Loading branch information
Showing
7 changed files
with
254 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
class ServerException implements Exception {} | ||
|
||
class ConnectivityException implements Exception {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
abstract class NetworkInfo { | ||
Future<bool> checkConnection(); | ||
} |
5 changes: 5 additions & 0 deletions
5
lib/features/news_feed/data/data_sources/news_feed_remote_data_source.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import 'package:news_app/features/news_feed/data/models/news_feed_model.dart'; | ||
|
||
abstract class NewsFeedRemoteDataSource { | ||
Future<NewsFeedModel> getNewsFeedForCategory(String category); | ||
} |
31 changes: 31 additions & 0 deletions
31
lib/features/news_feed/data/repositories/news_feed_repository_impl.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import 'package:dartz/dartz.dart'; | ||
import 'package:news_app/core/error/exceptions.dart'; | ||
import 'package:news_app/core/error/failures.dart'; | ||
import 'package:news_app/core/platform/network_info.dart'; | ||
import 'package:news_app/features/news_feed/data/data_sources/news_feed_remote_data_source.dart'; | ||
import 'package:news_app/features/news_feed/domain/entities/news_feed_entity.dart'; | ||
import 'package:news_app/features/news_feed/domain/repositories/news_feed_repository.dart'; | ||
|
||
class NewsFeedRepositoryImpl extends NewsFeedRepository { | ||
final NetworkInfo networkInfo; | ||
final NewsFeedRemoteDataSource remoteDataSource; | ||
|
||
NewsFeedRepositoryImpl( | ||
{required this.networkInfo, required this.remoteDataSource}); | ||
|
||
@override | ||
Future<Either<Failure, NewsFeedEntity>> getNewsFeed(String category) async { | ||
try { | ||
await networkInfo.checkConnection(); | ||
final NewsFeedEntity remoteTrivia = | ||
await remoteDataSource.getNewsFeedForCategory(category); | ||
// can also cache the data when the remote fetch is successful | ||
// and return the cached value if there is no network connection | ||
return Right(remoteTrivia); | ||
} on ConnectivityException { | ||
return Left(ConnectivityFailure()); | ||
} on ServerException { | ||
return Left(ServerFailure()); | ||
} | ||
} | ||
} |
128 changes: 128 additions & 0 deletions
128
test/features/news_feed/data/repositories/news_feed_repository_impl_test.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import 'package:dartz/dartz.dart'; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
import 'package:mockito/annotations.dart'; | ||
import 'package:mockito/mockito.dart'; | ||
import 'package:news_app/core/error/exceptions.dart'; | ||
import 'package:news_app/core/error/failures.dart'; | ||
import 'package:news_app/core/platform/network_info.dart'; | ||
import 'package:news_app/features/news_feed/data/data_sources/news_feed_remote_data_source.dart'; | ||
import 'package:news_app/features/news_feed/data/models/news_feed_model.dart'; | ||
import 'package:news_app/features/news_feed/data/repositories/news_feed_repository_impl.dart'; | ||
import 'package:news_app/features/news_feed/domain/entities/news_feed_entity.dart'; | ||
|
||
import '../../../../core/fixtures/api_configs.dart'; | ||
import 'news_feed_repository_impl_test.mocks.dart'; | ||
|
||
//mock the abstract network info (core/platform) | ||
@GenerateNiceMocks([MockSpec<NetworkInfo>()]) | ||
//mock the abstract remote data source | ||
@GenerateNiceMocks([MockSpec<NewsFeedRemoteDataSource>()]) | ||
void main() { | ||
late MockNetworkInfo mockNetworkInfo; | ||
late MockNewsFeedRemoteDataSource mockNewsFeedRemoteDataSource; | ||
late NewsFeedRepositoryImpl repositoryImpl; | ||
|
||
setUp(() { | ||
mockNetworkInfo = MockNetworkInfo(); | ||
mockNewsFeedRemoteDataSource = MockNewsFeedRemoteDataSource(); | ||
repositoryImpl = NewsFeedRepositoryImpl( | ||
remoteDataSource: mockNewsFeedRemoteDataSource, | ||
networkInfo: mockNetworkInfo, | ||
); | ||
}); | ||
|
||
const testCategory = kNewsAPICategoryTechnology; | ||
const testNewsFeedModel = NewsFeedModel( | ||
status: "ok", | ||
totalResults: 1, | ||
articles: [ | ||
ArticlesModel( | ||
source: SourceModel( | ||
name: "Nintendo Life", | ||
), | ||
author: "Liam Doolan", | ||
title: | ||
"Metal Gear Solid: Master Collection Vol. 1 Resolution & Frame Rate Chart Released - Nintendo Life", | ||
description: "Here's how the Switch version compares", | ||
url: | ||
"https://www.nintendolife.com/news/2023/09/metal-gear-solid-master-collection-vol-1-resolution-and-frame-rate-chart-released", | ||
urlToImage: | ||
"https://images.nintendolife.com/9ae5106942e8a/1280x720.jpg", | ||
publishedAt: "2023-09-24T05:35:00Z", | ||
content: | ||
"Image: Konami\r\nHideo Kojima's legendary series Metal Gear Solid returns as a collection release this October on all platforms including the Nintendo Switch, and as part of this Konami has now shared … [+1295 chars]", | ||
) | ||
], | ||
); | ||
const NewsFeedEntity testNewsFeedEntity = testNewsFeedModel; | ||
|
||
group("getNewsFeed tests", () { | ||
test('should check if the device is online', () async { | ||
//arrange | ||
when(mockNetworkInfo.checkConnection()).thenAnswer((_) async => true); | ||
// act | ||
await repositoryImpl.getNewsFeed(testCategory); | ||
// assert | ||
verify(mockNetworkInfo.checkConnection()); | ||
}); | ||
|
||
group("device is online", () { | ||
setUp(() async { | ||
//always return true for this group | ||
when(mockNetworkInfo.checkConnection()).thenAnswer((_) async => true); | ||
}); | ||
|
||
test( | ||
'should return remote data when the call to remote data source is successful', | ||
() async { | ||
// arrange | ||
when(mockNewsFeedRemoteDataSource | ||
.getNewsFeedForCategory(testCategory)) | ||
.thenAnswer((_) async => testNewsFeedModel); | ||
// act | ||
final result = await repositoryImpl.getNewsFeed(testCategory); | ||
// assert | ||
verify(mockNewsFeedRemoteDataSource | ||
.getNewsFeedForCategory(testCategory)); | ||
expect(result, equals(const Right(testNewsFeedEntity))); | ||
}, | ||
); | ||
|
||
test( | ||
'should return ServerFailure when the call to remote data source is unsuccessful', | ||
() async { | ||
// arrange | ||
when(mockNewsFeedRemoteDataSource | ||
.getNewsFeedForCategory(testCategory)) | ||
.thenThrow(ServerException()); | ||
// act | ||
final result = await repositoryImpl.getNewsFeed(testCategory); | ||
// assert | ||
verify(mockNewsFeedRemoteDataSource | ||
.getNewsFeedForCategory(testCategory)); | ||
expect(result, equals(Left(ServerFailure()))); | ||
}, | ||
); | ||
}); | ||
|
||
group("device is offline", () { | ||
setUp(() async { | ||
//always return false for this group | ||
when(mockNetworkInfo.checkConnection()) | ||
.thenThrow(ConnectivityException()); | ||
}); | ||
|
||
test( | ||
"should return Connectivity Failure when there is no internet connection", | ||
() async { | ||
//arrange | ||
|
||
//act | ||
final result = await repositoryImpl.getNewsFeed(testCategory); | ||
//assert | ||
verifyZeroInteractions(mockNewsFeedRemoteDataSource); | ||
expect(result, Left(ConnectivityFailure())); | ||
}); | ||
}); | ||
}); | ||
} |
79 changes: 79 additions & 0 deletions
79
test/features/news_feed/data/repositories/news_feed_repository_impl_test.mocks.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// Mocks generated by Mockito 5.4.2 from annotations | ||
// in news_app/test/features/news_feed/data/repositories/news_feed_repository_impl_test.dart. | ||
// Do not manually edit this file. | ||
|
||
// ignore_for_file: no_leading_underscores_for_library_prefixes | ||
import 'dart:async' as _i4; | ||
|
||
import 'package:mockito/mockito.dart' as _i1; | ||
import 'package:news_app/core/platform/network_info.dart' as _i3; | ||
import 'package:news_app/features/news_feed/data/data_sources/news_feed_remote_data_source.dart' | ||
as _i5; | ||
import 'package:news_app/features/news_feed/data/models/news_feed_model.dart' | ||
as _i2; | ||
|
||
// ignore_for_file: type=lint | ||
// 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 | ||
// ignore_for_file: subtype_of_sealed_class | ||
|
||
class _FakeNewsFeedModel_0 extends _i1.SmartFake implements _i2.NewsFeedModel { | ||
_FakeNewsFeedModel_0( | ||
Object parent, | ||
Invocation parentInvocation, | ||
) : super( | ||
parent, | ||
parentInvocation, | ||
); | ||
} | ||
|
||
/// A class which mocks [NetworkInfo]. | ||
/// | ||
/// See the documentation for Mockito's code generation for more information. | ||
class MockNetworkInfo extends _i1.Mock implements _i3.NetworkInfo { | ||
@override | ||
_i4.Future<bool> checkConnection() => (super.noSuchMethod( | ||
Invocation.method( | ||
#checkConnection, | ||
[], | ||
), | ||
returnValue: _i4.Future<bool>.value(false), | ||
returnValueForMissingStub: _i4.Future<bool>.value(false), | ||
) as _i4.Future<bool>); | ||
} | ||
|
||
/// A class which mocks [NewsFeedRemoteDataSource]. | ||
/// | ||
/// See the documentation for Mockito's code generation for more information. | ||
class MockNewsFeedRemoteDataSource extends _i1.Mock | ||
implements _i5.NewsFeedRemoteDataSource { | ||
@override | ||
_i4.Future<_i2.NewsFeedModel> getNewsFeedForCategory(String? category) => | ||
(super.noSuchMethod( | ||
Invocation.method( | ||
#getNewsFeedForCategory, | ||
[category], | ||
), | ||
returnValue: _i4.Future<_i2.NewsFeedModel>.value(_FakeNewsFeedModel_0( | ||
this, | ||
Invocation.method( | ||
#getNewsFeedForCategory, | ||
[category], | ||
), | ||
)), | ||
returnValueForMissingStub: | ||
_i4.Future<_i2.NewsFeedModel>.value(_FakeNewsFeedModel_0( | ||
this, | ||
Invocation.method( | ||
#getNewsFeedForCategory, | ||
[category], | ||
), | ||
)), | ||
) as _i4.Future<_i2.NewsFeedModel>); | ||
} |