前言:
作爲移動應用的開發者,會編寫自動化測試代碼將大大解放我們的雙手。移動應用的測試工作量通常很大,爲了驗證真實用戶的使用體驗,往往需要跨越多個Android和iOS平臺的物理設備手動完成測試。隨着產品功能不斷迭代累積,測試工作量和複雜度也隨之大幅增長,手動測試變得越來越困難,而自動化測試將重複的、機械的人工操作變爲自動化的驗證步驟,極大地節省人力、時間和硬件資源,從而提高了測試效率,保證了應用程序的穩定性和功能的完整性。接下來我簡單總結一下如何在Flutter通過integration test實現自動化集成測試並上傳到Firebase testlab的處理方案,有需要的話可以參考。
實現的步驟:
1. 在 pubspec.yaml 文件添加插件
dev_dependencies:
integration_test:
sdk: flutter
flutter_test:
sdk: flutter
2.在項目的根目錄創建integration_test和test_driver文件夾(與lib同一層目錄,否則自動測試跑不起來)
integration_test目錄:用於編寫集成測試的測試用例代碼
test目錄:用於編寫單元測試和組件測試的測試用例代碼
test_driver目錄:用於文本集成的調用驅動程序integration driver,使其能夠使用 flutter drive 命令運行新測試
integration_test/
testlab_login.dart
testlab_register.dart
lib/
...
test/
login_test.dart
register_test.dart
test_driver/
integration_test.dart
3.爲測試驅動程序腳本創建一個入口點integration_test.dart
import 'package:integration_test/integration_test_driver.dart';
Future<void> main() => integrationDriver();
4. 常用的自動化測試構造方法
(1) 常用的 expct 預期驗證:
findsOneWidget 驗證 widget 只在屏幕中出現一次
findsNothing 驗證沒有可被查找的 widgets
findsWidgets 驗證一個或多個 widgets 被找到
findsNWidgets 驗證特定數量的 widgets 被找到
static Future<void> testMethod01(
WidgetTester tester) async {
final Finder item1 = find.text('Hello');
final Finder item2 = find.text('Hi');
final Finder item3 = find.text('Other');
expect(item1, findsOneWidget);//findsOneWidget 驗證 widget 只在屏幕中出現一次
expect(item2, findsWidgets);//findsWidgets 驗證一個或多個 widgets 被找到
expect(item3, findsNothing);//findsNothing 驗證沒有可被查找的 widgets
await tester.longPress(item1);//輸入預期的內容
await tester.longPress(item2);
await tester.longPress(item3);
await tester.pumpAndSettle();
}
(2) 常用的finder構造函數:
find.text 通過特定文本 String 來查找 widget
find.byKey 通過 Key 來查找 widget
find.byType 通過已經指定的 Type 類型來查找 widget
static Future<void> testMethod02(
WidgetTester tester, String email) async {
//通過特定文本 String 來查找 widget
await tester.longPress(find.text("Next"));
//通過 Key 來查找 widget
await tester.longPress(find.byKey(const Key("k_key")));//在頁面的組件設置key
//通過 TextFormField 類型的來查找 widget
await tester.enterText(find.byType(TextFormField), email);
await tester.pumpAndSettle();
}
(3) WidgetTester 還提供文本輸入、點擊、拖動的相關方法:
tester.enterText(); //文本輸入
tester.tap(); //點擊
tester.longPress(); //長點擊
tester.drag(); //拖動
tester.pumpAndSettle(); //重新構建widget
static Future<void> testMethod03(
WidgetTester tester, String email) async {
//通過輸入的方式來查找 TextFormField 的類型的 widget
await tester.enterText(find.byType(TextFormField), email);
//通過點擊的方式查找特定文本 String 的 widget
await tester.tap(find.text("Next"));
//通過長點擊的方式查找特定文本 String 的 widget
await tester.longPress(find.text("Next"));
await tester.pumpAndSettle();
}
5.封裝自動化測試的用例代碼 (以登錄爲例)
class TestLabCommon {
static Future<void> testLanding(WidgetTester tester) async {
//通過長點擊的方式來查找顯示特定文本 String 的 widget
await tester.longPress(find.text("Login"));
//爲了保證模擬用戶交互實現後,widget 樹能重建
await tester.pumpAndSettle();
}
static Future<void> testLoginEmail(
WidgetTester tester, String email) async {
//通過輸入的方式來查找 TextFormField的類型的 widget
await tester.enterText(find.byType(TextFormField), email);
await tester.tap(find.text("Next"));
await tester.pumpAndSettle();
}
static Future<void> testLoginPassword(WidgetTester tester,String password) async {
//通過輸入的方式來查找 TextFormField 的類型的 widget
await tester.enterText(find.byType(TextFormField), password);
await tester.longPress(find.text("Next"));
await tester.pump(const Duration(seconds: 1));
await tester.pump(const Duration(seconds: 1));
await tester.pump(const Duration(seconds: 1)); //3秒
}
static Future<void> testLogin(WidgetTester tester, String email, String password) async {
await testLandingLogin(tester);
await testLoginNewUserEmail(tester, email);
await testLoginNewUserPassword(tester, password);
}
}
6.調用自動化測試的用例代碼
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
String groupDescription = '冒煙測試';
group(groupDescription, () {
String testcaseDescription = '登錄流程自動化測試';
testWidgets(testcaseDescription, (tester) async {
app.main();//調用app的入口函數
await tester.pumpAndSettle();
await TestLabCommon.testLogin(
tester, email, password);
});
});
}
7. 在 Firebase testlab 進行測試
Android 篇:
(1) 在 build.gradle 添加插件
android {
defaultConfig {
...
minSdkVersion 21
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
//添加
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
}
dependencies {
//添加
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test:runner:1.3.0'
androidTestImplementation 'androidx.test:rules:1.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}
(2) 創建一個新文件 android/app/src/androidTest/java/your/package/yourapp/ MainActivityTest.java
package uk.co.credito.staging;
import androidx.test.rule.ActivityTestRule;
import org.junit.Rule;
import org.junit.runner.RunWith;
import dev.flutter.plugins.integration_test.*;
@RunWith(FlutterTestRunner.class)
public class MainActivityTest {
@Rule
public ActivityTestRule<MainActivity> rule = new ActivityTestRule<>(MainActivity.class, true, false);
}
(3) 本地運行自動化測試腳本代碼
flutter test integration_test/testlab_login.dart
(4) 運行自動化測試腳本代碼
flutter drive \
--driver=test_driver/integration_test.dart \
--target=integration_test/testlab_login.dart
(5) 打包生成測試版本的 apk
pushd android
flutter build apk
./gradlew app:assembleAndroidTest
./gradlew app:assembleDebug -Ptarget=integration_test/testlab_login.dart
popd
(6) 上傳 apk 到 Firebase testlab
> App apk 位置:
/build/app/outputs/apk/debug/app-debug.apk
> Test app 位置:
/build/app/outputs/apk/androidTest/app-debug-androidTest.apk
(7) 在 Firebase testlab 創建自定義的 Android 設備
(8) 選擇 integration test 插樁測試,上傳 apk 到 Firebase testlab
(9)選擇自定義的 Android 設備並運行測試
(10) Firebase testlab 插樁測試的詳情,可查看 Android 日誌和視頻
iOS篇:
(1) 在ios/Podfile文件添加
target 'Runner' do
# use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
(2) 運行自動化測試腳本代碼
flutter build ios --config-only integration_test/testlab_login.dart
(3) 添加RunnerTests.m的測試文件
@import XCTest;
@import integration_test;
INTEGRATION_TEST_IOS_RUNNER(RunnerTests)
(4) 在Xcode運行自動化測試代碼
1. run flutter build ios --config-only integration_test/testlab_login.dart
2. open ios/Runner.xcworkspace
3. run 'RunnerTests' in Xcode
(5)在 Flutter 的根目錄運行自動化腳本代碼並打包生成測試版本的應用程序
../build/ios_integ/Build/Products/ios_tests.zip
output=""../build/ios_integ""
product=""build/ios_integ/Build/Products""
dev_target=""16.2""
flutter build ios integration_test/testlab_login.dart --simulator
pushd ios
xcodebuild -workspace Runner.xcworkspace -scheme Runner -config Flutter/Release.xcconfig -derivedDataPath $output -sdk iphoneos build-for-testing
popd
pushd $product
zip -r ""ios_tests.zip"" ""Release-iphoneos"" ""Runner_iphoneos$dev_target-arm64.xctestrun""
popd
(6)在 Firebase testlab 創建自定義的 iOS 設備
(7)選擇 XCTest測試,上傳 ios_tests.zip 到 Firebase testlab
(8)Firebase testlab 插樁測試的詳情,可查看 iOS 日誌和視頻
總結:Flutter 通過 Integration test 實現 Android/iOS 自動化集成測試並上傳到 Firebase testlab 的功能,親測有效,如果大家有什麼疑問的話,歡迎留言聯繫我。整理不易,轉載請標明出處,謝謝!