Skip to content

Commit 7677b3d

Browse files
author
Matej Resetar
committed
9 - Remote Data Source
1 parent 5da246b commit 7677b3d

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-0
lines changed

lib/features/number_trivia/data/datasources/number_trivia_remote_data_source.dart

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
import 'dart:convert';
2+
3+
import 'package:http/http.dart' as http;
4+
import 'package:meta/meta.dart';
5+
6+
import '../../../../core/error/exceptions.dart';
17
import '../models/number_trivia_model.dart';
28

39
abstract class NumberTriviaRemoteDataSource {
@@ -11,3 +17,32 @@ abstract class NumberTriviaRemoteDataSource {
1117
/// Throws a [ServerException] for all error codes.
1218
Future<NumberTriviaModel> getRandomNumberTrivia();
1319
}
20+
21+
class NumberTriviaRemoteDataSourceImpl implements NumberTriviaRemoteDataSource {
22+
final http.Client client;
23+
24+
NumberTriviaRemoteDataSourceImpl({@required this.client});
25+
26+
@override
27+
Future<NumberTriviaModel> getConcreteNumberTrivia(int number) =>
28+
_getTriviaFromUrl('http://numbersapi.com/$number');
29+
30+
@override
31+
Future<NumberTriviaModel> getRandomNumberTrivia() =>
32+
_getTriviaFromUrl('http://numbersapi.com/random');
33+
34+
Future<NumberTriviaModel> _getTriviaFromUrl(String url) async {
35+
final response = await client.get(
36+
url,
37+
headers: {
38+
'Content-Type': 'application/json',
39+
},
40+
);
41+
42+
if (response.statusCode == 200) {
43+
return NumberTriviaModel.fromJson(json.decode(response.body));
44+
} else {
45+
throw ServerException();
46+
}
47+
}
48+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import 'dart:convert';
2+
3+
import 'package:clean_architecture_tdd_course/core/error/exceptions.dart';
4+
import 'package:clean_architecture_tdd_course/features/number_trivia/data/datasources/number_trivia_remote_data_source.dart';
5+
import 'package:clean_architecture_tdd_course/features/number_trivia/data/models/number_trivia_model.dart';
6+
import 'package:mockito/mockito.dart';
7+
import 'package:flutter_test/flutter_test.dart';
8+
import 'package:matcher/matcher.dart';
9+
import 'package:http/http.dart' as http;
10+
11+
import '../../../../fixtures/fixture_reader.dart';
12+
13+
class MockHttpClient extends Mock implements http.Client {}
14+
15+
void main() {
16+
NumberTriviaRemoteDataSourceImpl dataSource;
17+
MockHttpClient mockHttpClient;
18+
19+
setUp(() {
20+
mockHttpClient = MockHttpClient();
21+
dataSource = NumberTriviaRemoteDataSourceImpl(client: mockHttpClient);
22+
});
23+
24+
void setUpMockHttpClientSuccess200() {
25+
when(mockHttpClient.get(any, headers: anyNamed('headers')))
26+
.thenAnswer((_) async => http.Response(fixture('trivia.json'), 200));
27+
}
28+
29+
void setUpMockHttpClientFailure404() {
30+
when(mockHttpClient.get(any, headers: anyNamed('headers')))
31+
.thenAnswer((_) async => http.Response('Something went wrong', 404));
32+
}
33+
34+
group('getConcreteNumberTrivia', () {
35+
final tNumber = 1;
36+
final tNumberTriviaModel =
37+
NumberTriviaModel.fromJson(json.decode(fixture('trivia.json')));
38+
39+
test(
40+
'''should perform a GET request on a URL with number
41+
being the endpoint and with application/json header''',
42+
() async {
43+
// arrange
44+
setUpMockHttpClientSuccess200();
45+
// act
46+
dataSource.getConcreteNumberTrivia(tNumber);
47+
// assert
48+
verify(mockHttpClient.get(
49+
'http://numbersapi.com/$tNumber',
50+
headers: {
51+
'Content-Type': 'application/json',
52+
},
53+
));
54+
},
55+
);
56+
57+
test(
58+
'should return NumberTrivia when the response code is 200 (success)',
59+
() async {
60+
// arrange
61+
setUpMockHttpClientSuccess200();
62+
// act
63+
final result = await dataSource.getConcreteNumberTrivia(tNumber);
64+
// assert
65+
expect(result, equals(tNumberTriviaModel));
66+
},
67+
);
68+
69+
test(
70+
'should throw a ServerException when the response code is 404 or other',
71+
() async {
72+
// arrange
73+
setUpMockHttpClientFailure404();
74+
// act
75+
final call = dataSource.getConcreteNumberTrivia;
76+
// assert
77+
expect(() => call(tNumber), throwsA(TypeMatcher<ServerException>()));
78+
},
79+
);
80+
});
81+
82+
group('getRandomNumberTrivia', () {
83+
final tNumberTriviaModel =
84+
NumberTriviaModel.fromJson(json.decode(fixture('trivia.json')));
85+
86+
test(
87+
'''should perform a GET request on a URL with number
88+
being the endpoint and with application/json header''',
89+
() async {
90+
// arrange
91+
setUpMockHttpClientSuccess200();
92+
// act
93+
dataSource.getRandomNumberTrivia();
94+
// assert
95+
verify(mockHttpClient.get(
96+
'http://numbersapi.com/random',
97+
headers: {
98+
'Content-Type': 'application/json',
99+
},
100+
));
101+
},
102+
);
103+
104+
test(
105+
'should return NumberTrivia when the response code is 200 (success)',
106+
() async {
107+
// arrange
108+
setUpMockHttpClientSuccess200();
109+
// act
110+
final result = await dataSource.getRandomNumberTrivia();
111+
// assert
112+
expect(result, equals(tNumberTriviaModel));
113+
},
114+
);
115+
116+
test(
117+
'should throw a ServerException when the response code is 404 or other',
118+
() async {
119+
// arrange
120+
setUpMockHttpClientFailure404();
121+
// act
122+
final call = dataSource.getRandomNumberTrivia;
123+
// assert
124+
expect(() => call(), throwsA(TypeMatcher<ServerException>()));
125+
},
126+
);
127+
});
128+
}

0 commit comments

Comments
 (0)