使用 TDD + Clean Architecture 開發 Flutter 專案課程筆記 7 ~ 9

hands typing on a laptop keyboard Flutter
Photo by cottonbro studio on Pexels.com

前言

這部分也在講 data layer 的內容,不過會更專注在 data source 裡面的東西。

筆記

Flutter TDD Clean Architecture Course [7] – Network Info

這集一開始導入一個 3rd party lib,專門用來確認網路狀態。這個 lib 直接連各大網路服務的 IP,概念簡單但很準確;不過 Github 上面有條滿可怕的 issue,正式版可能要考慮一下:

Don't use it on production for iOS! · Issue #7 · komapeb/data_connection_checker
In current version it will never pass Apple AppStore app approval process, because it does not work in IPv6 network. I w...
test(
  'should forward the call of connectionChecker',
  () async {
    // arrange
    when(mockDataConnectionChecker.hasConnection).thenAnswer((_) async => true);
    // act
    final result = await networkInfo.isConnected;
    // assert
    verify(mockDataConnectionChecker.hasConnection);
    expect(result, true);
  },
);
test(
  'should forward the call to connectionChecker',
  () async {
    // arrange
    final tHasConnectionFuture = Future.value(true);
    when(mockDataConnectionChecker.hasConnection).thenAnswer((_) => tHasConnectionFuture);
    // act
    final result = networkInfo.isConnected;
    // assert
    verify(mockDataConnectionChecker.hasConnection);
    expect(result, tHasConnectionFuture);
  },
);

後面在寫 NetworkInfo 的測試時,有針對回傳 true 改成 Future.value(true),主要是想確認 connectionCheck 傳的 object 真的是自己 mock 的那份,如此一來就是直接比記憶體位置,可以少寫一次測回傳 false 的測試。

Flutter TDD Clean Architecture Course [8] – Local Data Source

這集都在講 SharedPreferences 的測試與實作,滿單純的。

test('should throw a CacheException when there is not a cached value', () {
  // arrange
  when(mockSharedPreferences.getString(any)).thenReturn(null);
  // act
  // Not calling the method here, just storing it inside a call variable
  final call = dataSource.getLastNumberTrivia;
  // assert
  // Calling the method happens from a higher-order function passed.
  // This is needed to test if calling a method throws an exception.
  expect(() => call(), throwsA(isA<CacheException>()));
});

影片提到的 TypeMatcher 已經 deprecated,要改用 isA<CacheException>() 來取代。

  @override
  Future<void> cacheNumberTrivia(NumberTriviaModel model) {
    return sharedPreferences.setString(
        CACHED_NUMBER_TRIVIA, json.encode(model.toJson()));
  }

結尾的 return type 明明是 Future<bool>,但居然還可以正常 compile,為什麼會通過啊?事後有換一個 void 以外的型別,此時 IDE 就會跳警告了,因此可以確定是 void 造成的魔法,但這魔法讓人潔癖發作。

Flutter TDD Clean Architecture Course [9] – Remote Data Source

這集一樣是在處理 data source,跟上一集的差異就是處理 API 的部分。處理 exception 一樣有 TypeMatcher 已經 deprecated 的問題,需要留意。

專案連結

想看我實作的完整專案程式內容請瀏覽我的 github:

留言列表

Copied title and URL