yii.
← Writing
Flutter 技術 · · 3 min read

教你為 Riverpod 2.0 撰寫 Flutter 測試,使用 Mocktail 讓你輕鬆不畏懼! part.1

這篇寫於 2022 年。工具和 API 變化很快,部分步驟可能已經不適用。

說明 Mocktail 幾個常用的 API


Mocktail#

本文都會使用到 Mocktail 套件,優點是方便設置假資料,只需要一行即可使用 Mock class 開始測試,不需要額外生成測試代碼。透過 Mocktail 我們需要建立一個 Mock class 並繼承 Mock,代表可以進行假資料的驗證。接著實作定義好的介面,讓我們針對每個函式進行資料偽造。

提醒:建議開發都以 DI 去進行實作,其中的依賴反轉原則為每個服務以及資料類定義抽象介面,提供靈活性以及測試性。

// Mock class
class MockLocalStorage extends Mock implements LocalStorage {}

abstract class LocalStorage {
  Future<void> init();
  bool has(String key);
  Future<String?> get(String key);
  Future<void> set(String key, dynamic data);
}

mocktail | Dart PackageMock library for Dart inspired by mockito. Mocktail focuses on providing a familiar, simple API for creating mocks in…pub.dev

API for arrangement#

when()#

  • 當做了什麼事
  • 裡面通常放函式

thenReturn()#

函式為同步,返回同步資料

when(() => storage.has('isGood')).thenReturn((_) => true);

thenAnswer()#

函式為非同步,返回非同步資料

// 1. 
when(() => storage.get('isGood')).thenAnswer((_) async => 'true');
// 2.
when(() => storage.get('isGood')).thenAnswer((_) => Future.value('true'));

thenThrow()#

拋出 Exception,模擬出錯的情況

when(() => storage.has('isGood')).thenThrow(Exception('Can not get data!'));

API for verification#

expect()#

期望操作能得到什麼結果,檢查是否跟自己前面安排的偽造資料相同,驗證資料在邏輯處理後是否能給予預期結果。

expect(getAppThemeMode(), const AsyncData<ThemeMode>(ThemeMode.dark));

Ex: 透過 getAppThemeMode() 取得 ThemeMode,因為它為 FutureProvider 有非同步處理,我預期會得到指定的 AsyncData<ThemeMode>

expectLater()#

跟 except 一樣,只是裡面先進行非同步操作

await expectLater(() async => getAppThemeModeAsync(), throwsA(isA<Exception>()));

Ex: 透過 getAppThemeModeAsync() 取得 ThemeMode,前面安排在取資料的過程會拋出例外,所去預期會有 Exception

verify()#

  • 驗證某個函式是否被呼叫或使用過,也可以指定使用過的次數,檢查跟實際我們想要的情境是否相同。
  • 驗證過的操作或流程會被後面忽略,不能重複相同驗證否則會報錯
// Do some operation
final bool isGood = checkIsGood();
.
.
.

/// Choose one of two ways
// 1.
verify(() => storage.get('isGood'))
// 2.
verify(() => storage.get('isGood')).called(1);

Ex: 使用到 checkIsGood() 檢查狀態,裡面可能有一些邏輯,其中包含跟 storage 拿資料,我在後面驗證它實際上函式有沒有被呼叫,也檢查是否只呼叫過一次

verifyInOrder()#

驗證多個情況,照順序檢查是否正確,每個情境只有一個,不行重複確認

verifyInOrder([
 // Get current ThemeMode
  () => listener(null, const AsyncLoading<ThemeMode>()),
  () => listener(const AsyncLoading<ThemeMode>(), const AsyncData<ThemeMode>(ThemeMode.light)),
 
 // Change to ThemeMode.dark
  () => listener(const AsyncData(ThemeMode.light), const AsyncData(ThemeMode.dark)),
]);

Ex: 檢查更新 ThemeMode 的情境,從 ThemeMode.light 切換到 ThemeMode.dark

verifyNoMoreInteractions()#

驗證某個物件、函式是否沒有新的存取和互動了

verifyNoMoreInteractions(storage);

verifyNever()#

驗證物件、函式是否從來沒有使用過

verifyNever(storage.get('isGood'))

Matcher#

any()#

代表任何東西,可能是物件、函式,當無法百分百給予實際值的時候很適合使用

any(that: )#

檢查結果是否為指定型別,可以搭配 isA<XXX>()

any(
  that: isA<AsyncError<ThemeMode>>(),
),

到這邊休息一下,我想你已經大概了解一些寫測試的技巧了,如果準備好的話,可以先嘗試使用 Mocktail 撰寫簡易的測試,慢慢熟悉它

下一篇#

教你為 Riverpod 2.0 撰寫 Flutter 測試,使用 Mocktail 讓你輕鬆不畏懼! part.2測試幾個開發常遇到的 Riverpod 使用情境yii · writing


其他文章#

關於我#

贊助#

謝謝你花費時間看完,非常感謝!

如果覺得文章不錯的話可以贊助,讓我有更多動力和熱情分享學習紀錄和生活!請我喝一杯咖啡吧~

https://www.buymeacoffee.com/yiichenhi

最後#

希望有幫助到你/妳,歡迎追蹤我,方便瀏覽最新的文章~

本文原刊登於 Medium。