Skip to content

Commit 9eeb2f9

Browse files
authored
doc: move 'Suggested Dependency Relationship' upwords in the README file (#84)
Closes #83
1 parent 124a4b7 commit 9eeb2f9

File tree

2 files changed

+86
-32
lines changed

2 files changed

+86
-32
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Changed
11+
12+
- move 'Suggested Dependency Relationship' section upwards in the README file —
13+
[83](https://github.com/dartoos-dev/json_cache/issues/83).
14+
1015
## [1.2.4] - 2022-07-26
1116

1217
### Fixed

README.md

Lines changed: 81 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Rultor.com](https://www.rultor.com/b/dartoos-dev/json_cache)](https://www.rultor
2323

2424
- [Overview](#overview)
2525
- [Getting Started](#getting-started)
26+
- [Suggested Dependency Relationship](#suggested-dependency-relationship)
2627
- [Implementations](#implementations)
2728
- [JsonCacheMem — Thread-safe In-memory cache](#jsoncachemem)
2829
- [JsonCachePrefs — SharedPreferences](#jsoncacheprefs)
@@ -32,8 +33,8 @@ Rultor.com](https://www.rultor.com/b/dartoos-dev/json_cache)](https://www.rultor
3233
- [JsonCacheHive — Hive](#jsoncachehive)
3334
- [JsonCacheCrossLocalStorage — CrossLocalStorage](#jsoncachecrosslocalstorage)
3435
- [Unit Test Tips](#unit-test-tips)
35-
- [Suggested Dependency Relationship](#suggested-dependency-relationship)
36-
- [Using Fake Implementation](#using-fake-implementation)
36+
- [Mocking](#mocking)
37+
- [Fake Implementations](#using-fake-implementation)
3738
- [Widget Testing](#widget-testing)
3839
- [Example of Widget Test Code](#example-of-widget-test-code)
3940
- [SharedPreferences in Tests](#sharedpreferences-in-tests)
@@ -99,7 +100,7 @@ represents the name of a single data group. For example:
99100

100101
```dart
101102
'profile': {'name': 'John Doe', 'email': '[email protected]', 'accountType': 'premium'};
102-
'preferences': {'theme': {'dark': true}, 'notifications':{'enabled': true}}
103+
'preferences': {'theme': {'dark': true}, 'notifications': {'enabled': true}}
103104
```
104105

105106
Above, the _profile_ key is associated with profile-related data, while
@@ -114,6 +115,39 @@ await jsonCache.refresh('profile', {'name': 'John Doe', 'email': 'johndoe@email.
114115
await jsonCache.refresh('preferences', {'theme': {'dark': true}, 'notifications':{'enabled': true}});
115116
```
116117

118+
### Suggested Dependency Relationship
119+
120+
Whenever a function, method, or class needs to interact with cached user data,
121+
it should do so via a reference to the `JsonCache` interface.
122+
123+
See the code snippet below:
124+
125+
```dart
126+
/// Stores/retrieves user data from the device's local storage.
127+
class JsonCacheRepository implements ILocalRepository {
128+
/// Sets the [JsonCache] instance.
129+
const JsonCacheRepository(this._cache);
130+
// This class depends on an interface rather than any actual implementation
131+
final JsonCache _cache;
132+
133+
/// Retrieves a cached email by [userId] or `null` if not found.
134+
@override
135+
Future<String?> getUserEmail(String userId) async {
136+
final userData = await _cache.value(userId);
137+
if (userData != null) {
138+
// the email value or null if absent.
139+
return userData['email'] as String?;
140+
}
141+
// There is no data associated with [userId].
142+
return null;
143+
}
144+
}
145+
```
146+
147+
By depending on an interface rather than an actual implementation, your code
148+
becomes [loosely coupled](https://en.wikipedia.org/wiki/Loose_coupling) to this
149+
package — which makes unit testing a lot easier.
150+
117151
## Implementations
118152

119153
The library
@@ -269,43 +303,58 @@ is an implementation on top of the
269303
This package has been designed with unit testing in mind. This is one of the
270304
reasons for the existence of the `JsonCache` interface.
271305

272-
### Suggested Dependency Relationship
306+
### Mocking
273307

274-
Whenever a function, method, or class needs to interact with user data, it
275-
should do so via a reference to the `JsonCache` interface rather than relying on
276-
an actual implementation.
308+
Since `JsonCache` is the core interface of this package, you can easily
309+
[mock](https://docs.flutter.dev/cookbook/testing/unit/mocking) a implementation
310+
that suits you when unit testing your code.
277311

278-
See the code snippet below:
312+
For example, with [mocktail](https://pub.dev/packages/mocktail) a mock
313+
implementation should look like this:
279314

280315
```dart
281-
/// Stores/retrieves user data from the device's local storage.
282-
class JsonCacheRepository implements ILocalRepository {
283-
/// Sets the [JsonCache] instance.
284-
const JsonCacheRepository(this._cache);
285-
// This class depends on an interface rather than any actual implementation
286-
final JsonCache _cache;
316+
import 'package:mocktail/mocktail.dart';
287317
288-
/// Retrieves a cached email by [userId] or `null` if not found.
289-
@override
290-
Future<String?> getUserEmail(String userId) async {
291-
final userData = await _cache.value(userId);
292-
if (userData != null) {
293-
// the email value or null if absent.
294-
return userData['email'] as String?;
295-
}
296-
// There is no data associated with [userId].
297-
return null;
298-
}
318+
class JsonCacheMock extends Mock implements JsonCache {}
319+
320+
void main() {
321+
// the mock instance.
322+
final jsonCacheMock = JsonCacheMock();
323+
324+
test('should retrieve the preferences data', () async {
325+
// Stub the 'value' method.
326+
when(() => jsonCacheMock.value('preferences')).thenAnswer(
327+
(_) async => <String, dynamic>{
328+
'theme': {'dark': true},
329+
'notifications': {'enabled': true}
330+
},
331+
);
332+
333+
// Verify no interactions have occurred.
334+
verifyNever(() => jsonCacheMock.value('preferences'));
335+
336+
// Interact with the jsonCacheMock instance.
337+
final preferencesData = await jsonCacheMock.value('preferences');
338+
339+
// Assert
340+
expect(
341+
preferencesData,
342+
equals(
343+
<String, dynamic>{
344+
'theme': {'dark': true},
345+
'notifications': {'enabled': true}
346+
},
347+
),
348+
);
349+
350+
// Check if the interaction occurred only once.
351+
verify(() => jsonCacheMock.value('preferences')).called(1);
352+
});
299353
}
300-
```
301354
302-
By depending on an interface rather than an actual implementation, the code
303-
above is [loosely coupled](https://en.wikipedia.org/wiki/Loose_coupling) to this
304-
package — which means it's easy to test as you can
305-
[mock](https://docs.flutter.dev/cookbook/testing/unit/mocking) the `JsonCache`
306-
dependency.
355+
```
307356

308-
### Using Fake Implementation
357+
### Fake Implementations
309358

310359
In addition to mocking, there is another approach to unit testing: making use of
311360
a 'fake' implementation. Usually this so called 'fake' implementation provides

0 commit comments

Comments
 (0)