Skip to content

Commit 5370231

Browse files
authored
doc: add unit testing tips to the README file (#75)
Closes #73
1 parent 1d75f6d commit 5370231

File tree

4 files changed

+97
-24
lines changed

4 files changed

+97
-24
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+
### Added
11+
12+
- Unit testing tips to the README file —
13+
[73](https://github.com/dartoos-dev/json_cache/issues/73).
14+
1015
## [1.2.1] - 2022-04-02
1116

1217
### Changed

README.md

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ Rultor.com](https://www.rultor.com/b/dartoos-dev/json_cache)](https://www.rultor
3131
- [JsonCacheLocalStorage — LocalStorage](#jsoncachelocalstorage)
3232
- [JsonCacheHive — Hive](#jsoncachehive)
3333
- [JsonCacheCrossLocalStorage — CrossLocalStorage](#jsoncachecrosslocalstorage)
34+
- [Unit Test Tips](#unit-test-tips)
35+
- [Suggested Dependency Relationship](#suggested-dependency-relationship)
36+
- [Using Fake Implementation](#using-fake-implementation)
37+
- [Widget Testing](#widget-testing)
38+
- [Example of Widget Test Code](#example-of-widget-test-code)
3439
- [Demo application](#demo-application)
3540
- [Contribute](#contribute)
3641
- [References](#references)
@@ -256,7 +261,80 @@ is an implementation on top of the
256261
257262
final LocalStorageInterface prefs = await LocalStorage.getInstance();
258263
final JsonCache jsonCache = JsonCacheMem(JsonCacheCrossLocalStorage(prefs));
259-
264+
```
265+
266+
## Unit Test Tips
267+
268+
This package has been designed with unit testing in mind. This is one of the
269+
reasons for the existence of the `JsonCache` interface.
270+
271+
### Suggested Dependency Relationship
272+
273+
Whenever a function, method, or class needs to interact with user data, it
274+
should do so via a reference to the `JsonCache` interface rather than relying on
275+
an actual implementation.
276+
277+
See the code snippet below:
278+
279+
```dart
280+
/// Stores/retrieves user data from the device's local storage.
281+
class JsonCacheRepository implements ILocalRepository {
282+
/// Sets the [JsonCache] instance.
283+
const JsonCacheRepository(this._cache);
284+
// This class depends on an interface rather than any actual implementation
285+
final JsonCache _cache;
286+
287+
/// Retrieves a cached email by [userId] or `null` if not found.
288+
@override
289+
Future<String?> getUserEmail(String userId) async {
290+
final userData = await _cache.value(userId);
291+
if (userData != null) {
292+
// the email value or null if absent.
293+
return userData['email'] as String?;
294+
}
295+
// There is no data associated with [userId].
296+
return null;
297+
}
298+
}
299+
```
300+
301+
By depending on an interface rather than an actual implementation, the code
302+
above is [loosely coupled](https://en.wikipedia.org/wiki/Loose_coupling) to this
303+
package — which means it's easy to test as you can
304+
[mock](https://docs.flutter.dev/cookbook/testing/unit/mocking) the `JsonCache`
305+
dependency.
306+
307+
### Using Fake Implementation
308+
309+
In addition to mocking, there is another approach to unit testing: making use of
310+
a 'fake' implementation. Usually this so called 'fake' implementation provides
311+
the functionality required by the `JsonCache` interface without touching the
312+
device's local storage. An example of this implementation is the
313+
[JsonCacheFake](https://pub.dev/documentation/json_cache/latest/json_cache/JsonCacheFake-class.html)
314+
class — whose sole purpose is to help developers with unit tests.
315+
316+
### Widget Testing
317+
318+
Because of the asynchronous nature of dealing with cached data, you're better
319+
off putting all your test code inside a `tester.runAsync` method; otherwise,
320+
your test case may stall due to a
321+
[deadlock](https://en.wikipedia.org/wiki/Deadlock) caused by a [race
322+
condition](https://stackoverflow.com/questions/34510/what-is-a-race-condition)
323+
as there might be multiple `Futures` trying to access the same resources.
324+
325+
#### Example of Widget Test Code
326+
327+
Your widget test code should look similar to the following code snippet:
328+
329+
```dart
330+
testWidgets('refresh cached value', (WidgetTester tester) async {
331+
final LocalStorage localStorage = LocalStorage('my_cached_data');
332+
final jsonCache = JsonCacheMem(JsonCacheLocalStorage(localStorage));
333+
tester.runAsync(() async {
334+
// asynchronous code inside runAsync.
335+
await jsonCache.refresh('test', <String, dynamic>{'aKey': 'aValue'});
336+
});
337+
});
260338
```
261339

262340
## Demo application
@@ -293,5 +371,4 @@ Make sure the command below **passes** before making a Pull Request.
293371

294372
## References
295373

296-
- [Caching for objects](https://www.pragmaticobjects.com/chapters/012_caching_for_objects.html)
297374
- [Dart and race conditions](https://pub.dev/packages/mutex)

analysis_options.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ linter:
1313
sort_constructors_first: true
1414
# Good packages document everything
1515
public_member_api_docs: true
16-
# Always await.
17-
unawaited_futures: true
1816
always_declare_return_types: true
1917
cancel_subscriptions: true
2018
close_sinks: true

pubspec.lock

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ packages:
77
name: _fe_analyzer_shared
88
url: "https://pub.dartlang.org"
99
source: hosted
10-
version: "31.0.0"
10+
version: "41.0.0"
1111
analyzer:
1212
dependency: transitive
1313
description:
1414
name: analyzer
1515
url: "https://pub.dartlang.org"
1616
source: hosted
17-
version: "2.8.0"
17+
version: "4.2.0"
1818
args:
1919
dependency: transitive
2020
description:
@@ -57,13 +57,6 @@ packages:
5757
url: "https://pub.dartlang.org"
5858
source: hosted
5959
version: "1.3.1"
60-
cli_util:
61-
dependency: transitive
62-
description:
63-
name: cli_util
64-
url: "https://pub.dartlang.org"
65-
source: hosted
66-
version: "0.3.5"
6760
clock:
6861
dependency: transitive
6962
description:
@@ -77,7 +70,7 @@ packages:
7770
name: collection
7871
url: "https://pub.dartlang.org"
7972
source: hosted
80-
version: "1.15.0"
73+
version: "1.16.0"
8174
convert:
8275
dependency: transitive
8376
description:
@@ -126,7 +119,7 @@ packages:
126119
name: fake_async
127120
url: "https://pub.dartlang.org"
128121
source: hosted
129-
version: "1.2.0"
122+
version: "1.3.0"
130123
ffi:
131124
dependency: transitive
132125
description:
@@ -246,7 +239,7 @@ packages:
246239
name: js
247240
url: "https://pub.dartlang.org"
248241
source: hosted
249-
version: "0.6.3"
242+
version: "0.6.4"
250243
lint:
251244
dependency: "direct dev"
252245
description:
@@ -281,7 +274,7 @@ packages:
281274
name: material_color_utilities
282275
url: "https://pub.dartlang.org"
283276
source: hosted
284-
version: "0.1.3"
277+
version: "0.1.4"
285278
meta:
286279
dependency: transitive
287280
description:
@@ -323,7 +316,7 @@ packages:
323316
name: path
324317
url: "https://pub.dartlang.org"
325318
source: hosted
326-
version: "1.8.0"
319+
version: "1.8.1"
327320
path_provider:
328321
dependency: transitive
329322
description:
@@ -510,7 +503,7 @@ packages:
510503
name: source_span
511504
url: "https://pub.dartlang.org"
512505
source: hosted
513-
version: "1.8.1"
506+
version: "1.8.2"
514507
stack_trace:
515508
dependency: transitive
516509
description:
@@ -545,21 +538,21 @@ packages:
545538
name: test
546539
url: "https://pub.dartlang.org"
547540
source: hosted
548-
version: "1.19.5"
541+
version: "1.21.1"
549542
test_api:
550543
dependency: transitive
551544
description:
552545
name: test_api
553546
url: "https://pub.dartlang.org"
554547
source: hosted
555-
version: "0.4.8"
548+
version: "0.4.9"
556549
test_core:
557550
dependency: transitive
558551
description:
559552
name: test_core
560553
url: "https://pub.dartlang.org"
561554
source: hosted
562-
version: "0.4.9"
555+
version: "0.4.13"
563556
typed_data:
564557
dependency: transitive
565558
description:
@@ -573,7 +566,7 @@ packages:
573566
name: vector_math
574567
url: "https://pub.dartlang.org"
575568
source: hosted
576-
version: "2.1.1"
569+
version: "2.1.2"
577570
vm_service:
578571
dependency: transitive
579572
description:
@@ -624,5 +617,5 @@ packages:
624617
source: hosted
625618
version: "3.1.0"
626619
sdks:
627-
dart: ">=2.16.0 <3.0.0"
620+
dart: ">=2.17.0 <3.0.0"
628621
flutter: ">=2.5.0"

0 commit comments

Comments
 (0)