我想测试这个简单的应用程序:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
AppTheme theme = AppTheme();
FlutterLocalization localization = FlutterLocalization.instance;
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState(){
widget.theme.loadprefs();
widget.localization.init(
mapLocales: [
const MapLocale(
'en',
AppLocale.EN,
countryCode: 'US',
fontFamily: 'Font EN',
),
],
initLanguageCode: 'en',
);
widget.localization.onTranslatedLanguage = _onTranslatedLanguage;
}
void _onTranslatedLanguage(Locale? locale) {
setState(() {});
}
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => widget.theme,
child: Consumer<AppTheme>(
builder: (context, state, child) {
return MaterialApp(
// routerConfig: _appRouter.config(),
supportedLocales: widget.localization.supportedLocales,
localizationsDelegates: widget.localization.localizationsDelegates,
//
home: MyHomePage(title: "title"),
);
}
),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
color: backgroundColor(context),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(onPressed: (){
bool theme = (Provider.of<AppTheme>(context, listen: false).getCurrentTheme() == THEMES[0].theme);
int index = theme == true ? 1: 0;
Provider.of<AppTheme>(context, listen: false).setTheme(index);
}, child: Text("Change theme")),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
),
floatingActionButton: FloatingActionButton(
// Provide a Key to this button. This allows finding this
// specific button inside the test suite, and tapping it.
key: const Key('increment'),
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
测试:
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('end-to-end test', () {
testWidgets('tap on the floating action button, verify counter',
(tester) async {
// Load app widget.
// var theme = AppTheme();
// await theme.loadprefs();
await tester.pumpWidget( MyApp());
// Verify the counter starts at 0.
expect(find.text('0'), findsOneWidget);
// Finds the floating action button to tap on.
final fab = find.byKey(const ValueKey('increment'));
int i =0;
while(i<100) {
await tester.tap(fab);
i+=1;
}
await Future.delayed(Duration(minutes: 2));
// Emulate a tap on the floating action button.
// Trigger a frame.
await tester.pumpAndSettle();
// Verify the counter increments by 1.
expect(find.text('100'), findsOneWidget);
});
});
应用程序主题:
class AppTheme extends ChangeNotifier {
final String key = "theme";
SharedPreferences? _prefs;
late ThemeClass currentTheme;
List<ThemeClass> themes = THEMES;
AppTheme({initiate = true}) {
if (initiate) {
loadprefs();
}
}
switchtheme(ThemeClass theme) {
currentTheme = theme;
_saveprefs();
notifyListeners();
}
_initiateprefs() async {
_prefs ??= await SharedPreferences.getInstance();
}
getTheme(String theme){
return themes.where((element) => element.name == theme).first;
}
bool isCurrent(int index){
return currentTheme.name == themes[index].name;
}
loadprefs() async {
await _initiateprefs();
final n = _prefs?.getString(key);
if(n!= null) {
currentTheme = getTheme(n);
} else {
currentTheme = themes[0];
}
notifyListeners();
}
_saveprefs() async {
await _initiateprefs();
_prefs?.setString(key, currentTheme.name);
}
getCurrentTheme() {
return currentTheme.theme;
}
void setTheme(int index) {
switchtheme(themes[index]);
}
}
const Color DARK_BACKGROUND = Color(0xff26282D);
const Color THIRD_COLOR_DARK = Color(0xff3080CD);
const Color DARK_SECONDARY = Color(0xff12161C);
const Color DARK_SECONDARY_VARIANT = Color(0xff383A44);
const Color DARK_CONTRAST_COLOR = Color(0xffe2e4ea);
const Color DARK_SHADOW_COLOR = Color(0xff090A0D);
final List<ThemeClass> THEMES = [
ThemeClass(
name: 'Dark',
theme: themeDark
),
ThemeClass(
name: 'Light',
theme: themeLight
),
];
class ThemeClass{
final String name;
final ThemeData theme;
ThemeClass({required this.name, required this.theme});
}
final ThemeData themeLight = ThemeData(
bottomAppBarTheme: const BottomAppBarTheme(
color: Colors.pink,
),
primaryColor: Colors.amber,
);
final ThemeData themeDark = ThemeData(
bottomAppBarTheme: const BottomAppBarTheme(
color: DARK_BACKGROUND,
),
primaryColor: THIRD_COLOR_DARK,
secondaryHeaderColor: DARK_SECONDARY,
textTheme: darkText,
dividerColor: DARK_CONTRAST_COLOR,
indicatorColor: DARK_SECONDARY_VARIANT,
shadowColor: DARK_SHADOW_COLOR,
);
const TextTheme darkText = TextTheme(
headlineMedium: TextStyle(
fontSize: FONT_DISPLAY_LARGE,
fontWeight: FontWeight.w500,
color: FONT_COLOR_DARK,
// Add your font and other styles here
)
);
应用程序区域设置:
import 'package:intl/intl.dart';
import 'en.dart';
String getAbbreviationWithIndex(String abbr, int index) {
return '$abbr$index';
}
mixin AppLocale {
static const String increment = "increment";
static const Map<String, dynamic> EN = ENG;
static FlutterLocalization locale = FlutterLocalization.instance;
}
en.dart:
const Map<String, dynamic> ENG = {
"month": 'Month',
};
我的应用程序遇到一个问题,某些测试因找不到增量而失败。经过一番调查,我发现这些失败是在我向应用程序添加本地化时特别发生的。似乎本地化的引入在某种程度上导致测试失败,但我不完全确定为什么会发生这种情况。
您能帮我了解这个问题的根本原因吗?为什么向应用程序添加本地化会导致测试失败,特别是在查找增量时?此外,我可以采取哪些步骤来解决此问题并确保我的测试即使在启用本地化的情况下也能成功通过?
我在测试中做了一些更改,并且能够成功运行测试。 泵送应用程序后,它仍然将帧泵送到屏幕上,但无需等待完成,您就可以使用 key 查找元素。这就是导致问题的原因。
您可以在
await tester.pumpAndSettle();
之后立即使用
await tester.pumpWidget(MyApp());
await tester.pumpWidget(MyApp());
await tester.pumpAndSettle();
此外,最好在点击该项目之前先检查一下它。
final fab = find.byKey(const ValueKey('increment'));
expect(fab, findsOneWidget);
如果您想查看屏幕上发生的情况,请在点击后提供一个带有持续时间的pumpAndSettle
while (i < 100) {
await tester.tap(fab);
await tester.pumpAndSettle(const Duration(seconds: 1));
i += 1;
}
最终测试如下
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('end-to-end test', () {
testWidgets('tap on the floating action button, verify counter',
(tester) async {
await tester.pumpWidget(MyApp());
await tester.pumpAndSettle();
// Verify the counter starts at 0.
expect(find.text('0'), findsOneWidget);
// Finds the floating action button to tap on.
final fab = find.byKey(const ValueKey('increment'));
int i = 0;
while (i < 100) {
await tester.tap(fab);
//uncomment if you wanna see whats happening on the screen
//await tester.pumpAndSettle(const Duration(milliseconds: 300));
i += 1;
}
await tester.pumpAndSettle();
expect(find.text('100'), findsOneWidget);
});
});
}
改进建议: 在需要的地方使用静态/常量键总是更好,并使用它们而不是在代码中硬编码
const counterValueKey = 'counterValueKey';
const incrementButtonKey = 'incrementButtonKey';