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

Yii Chen
Flutter Formosa
Published in
7 min readDec 25, 2022

--

說明 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);
}

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 撰寫簡易的測試,慢慢熟悉它

下一篇

--

--

Yii Chen
Flutter Formosa

Flutter Lover || Organizer FlutterTaipei || Writer, Speaker || wanna make Flutter strong in Taiwan. https://linktr.ee/yiichenhi