Skip to content

test: 擴增各套件測試覆蓋率#156

Merged
abc873693 merged 3 commits intomasterfrom
test/150-expand-test-coverage
Mar 31, 2026
Merged

test: 擴增各套件測試覆蓋率#156
abc873693 merged 3 commits intomasterfrom
test/150-expand-test-coverage

Conversation

@abc873693
Copy link
Copy Markdown
Owner

摘要

為 4 個原本無測試的套件新增共 9 個測試檔案、129 個測試案例:

  • ap_common_flutter_core(3 個檔案、77 tests)
    • ApIcon:filled/outlined 兩種模式下 40+ icon 屬性的回傳值、index 計算
    • ApiResult.isSuccess:擴充方法的三種狀態判斷
    • DioException i18n 擴充:isJsonResponsefalconMessage 邏輯
  • ap_common_flutter_ui(2 個檔案、18 tests)
    • Toast 常數驗證、ToastWidget 定位邏輯(top/bottom)
    • ApTheme 常數、ThemeColor 資料類別、updateShouldNotify 變更偵測
  • ap_common_flutter_platform(2 個檔案、32 tests)
    • ApNotificationUtilgetDay 星期轉換、parseTime 時間解析與提前分鐘數、getNextWeekdayDateTime 日期計算
    • ApPreferenceUtil:String/Int/Double/Bool/StringList 的 get/set、AES 加解密、key 操作
  • ap_common_announcement_ui(2 個檔案、12 tests)
    • ImgurHelperImgbbHelper 圖片上傳:成功/錯誤/網路失敗的 ApiResult 回傳

測試計畫

  • melos run analyze — 9 個套件全數通過
  • ap_common_core — 38 tests passed
  • ap_common_flutter_core — 77 tests passed
  • ap_common_flutter_ui — 18 tests passed
  • ap_common_flutter_platform — 32 tests passed
  • ap_common_announcement_ui — 44 tests passed
  • 總計 209 tests 全數通過

Closes #150

…nouncement_ui

- flutter_core: ApIcon (filled/outlined), ApiResult.isSuccess extension,
  DioException i18n extensions (isJsonResponse, falconMessage)
- flutter_ui: Toast constants and ToastWidget positioning, ApTheme
  constants and updateShouldNotify logic
- flutter_platform: ApNotificationUtil (getDay, parseTime,
  getNextWeekdayDateTime), ApPreferenceUtil (all type get/set,
  encryption, key operations)
- announcement_ui: ImgurHelper and ImgbbHelper upload tests with
  ApiResult pattern (success, error, failure cases)

Total new tests: 129 (across 9 test files)

Closes #150
@github-actions
Copy link
Copy Markdown

Failed to generate code suggestions for PR

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive suite of unit and widget tests across several packages, including ap_common_announcement_ui, ap_common_flutter_core, ap_common_flutter_platform, and ap_common_flutter_ui. The new tests cover API helpers for image uploads, localization extensions for error handling, UI components like icons and themes, and utility classes for notifications and preferences. The review feedback suggests improving test assertions to verify specific error details, adding missing test cases for toast positioning, using a clock package to prevent flaky time-based tests, and adopting a mocking framework to simplify manual mock implementations.

});
});

group('uploadImage', () {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

這組測試中的錯誤情境(returns ApiError on non-200 statusreturns ApiError on 400 bad request)只驗證了回傳型別為 ApiError,但沒有檢查錯誤內容。這會讓一些潛在的 bug 溜走。

例如,ImgurHelper 的實作在收到 400 錯誤時,回傳的 ApiErrorstatusCode 卻是 201,這顯然是個錯誤。

建議讓測試更具體,去驗證 ApiError 內的 statusCodemessage,以確保錯誤處理的正確性。

範例如下:

test('returns ApiError on 400 bad request', () async {
  // ...
  final result = await helper.uploadImage(...);
  expect(result, isA<ApiError<String>>());
  final error = result as ApiError<String>;
  expect(error.response.statusCode, 400); // 這會捕捉到目前的 bug
});

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

目前會偏向替換掉 Imgur

});
});

group('ToastWidget', () {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

ToastWidget 的測試涵蓋了 topbottom 的對齊,但缺少了 Toast.center 的測試案例。目前的 ToastWidget 實作在 gravityToast.center 時,似乎無法正確處理垂直置中(它會被定位在頂部)。增加這個測試案例有助於發現並修復這個潛在的 bug。

建議新增一個 gravityToast.centertestWidgets

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

未來會重構這塊,也先無視

Comment on lines +111 to +121
test('should return a future date', () {
const TimeOfDay time = TimeOfDay(hour: 0, minute: 0);
final DateTime result =
util.getNextWeekdayDateTime(Day.monday, time);
// Result should be within 7 days from now
final DateTime now = DateTime.now();
expect(
result.difference(now).inDays,
lessThanOrEqualTo(7),
);
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

should return a future date 這個測試案例依賴於 DateTime.now(),這會導致測試結果不確定,可能變得不穩定。建議使用 clock 套件來固定測試時間,這樣就能對回傳的 DateTime 進行精確的斷言。

例如:

import 'package:clock/clock.dart';

test('should return next Monday if today is Wednesday', () {
  // A Wednesday
  withClock(Clock.fixed(DateTime(2023, 10, 25, 10, 0)), () { 
    const time = TimeOfDay(hour: 14, minute: 30);
    final result = util.getNextWeekdayDateTime(Day.monday, time);
    // Next Monday
    expect(result, DateTime(2023, 10, 30, 14, 30));
  });
});

Comment on lines +85 to +147
class _MockPreferenceUtil extends PreferenceUtil {
final Map<String, dynamic> _store = <String, dynamic>{};

@override
bool get isSupport => true;

@override
Future<void> setString(String key, String data) async =>
_store[key] = data;

@override
String getString(String key, String defaultValue) =>
(_store[key] as String?) ?? defaultValue;

@override
Future<void> setStringSecurity(String key, String data) async =>
_store[key] = data;

@override
String getStringSecurity(String key, String defaultValue) =>
(_store[key] as String?) ?? defaultValue;

@override
Future<void> setInt(String key, int data) async =>
_store[key] = data;

@override
int getInt(String key, int defaultValue) =>
(_store[key] as int?) ?? defaultValue;

@override
Future<void> setDouble(String key, double data) async =>
_store[key] = data;

@override
double getDouble(String key, double defaultValue) =>
(_store[key] as double?) ?? defaultValue;

@override
Future<void> setBool(String key, bool data) async =>
_store[key] = data;

@override
bool getBool(String key, bool defaultValue) =>
(_store[key] as bool?) ?? defaultValue;

@override
Future<void> setStringList(String key, List<String> data) async =>
_store[key] = data;

@override
List<String> getStringList(String key, List<String> defaultValue) =>
(_store[key] as List<String>?) ?? defaultValue;

@override
Set<String> getKeys() => _store.keys.toSet();

@override
Future<bool>? remove(String key) {
_store.remove(key);
return Future<bool>.value(true);
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

手動撰寫的 _MockPreferenceUtil 類別相當龐大,未來需要花費心力維護。建議考慮使用像 mockito 這樣的 mock 框架。它可以自動生成 mock 類別,減少樣板程式碼,讓測試更容易維護。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

只有這個的話先不用

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 30, 2026

Visit the preview URL for this PR (updated for commit 544327a):

https://ap-common--example-preview-z8c3pggl.web.app

(expires Tue, 07 Apr 2026 14:04:39 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: 61ecbaa5d4e2786c745a5e21d2a66c533b7f072b

…on utils

Replace DateTime.now() with clock.now() in getNextWeekdayDateTime to
enable deterministic testing. Update tests to use withClock for precise
date assertions instead of relying on current time.
@abc873693 abc873693 merged commit a130e7f into master Mar 31, 2026
3 checks passed
@abc873693 abc873693 deleted the test/150-expand-test-coverage branch March 31, 2026 14:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

test: 擴增各套件測試覆蓋率

1 participant