前言:
作为移动应用的开发者,会编写自动化测试代码将大大解放我们的双手。移动应用的测试工作量通常很大,为了验证真实用户的使用体验,往往需要跨越多个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 的功能,亲测有效,如果大家有什么疑问的话,欢迎留言联系我。整理不易,转载请标明出处,谢谢!