I want to test and cover both paths of a widget that uses kIsWeb. the class looks like this :
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (kIsWeb) {
return Text("I'm web");
} else {
return Text("I'm not web");
}
}
}
After searching a while I found a way to test this here : Testing kIsWeb constant in flutter
This is the Test class that I wrote :
class MockAppService extends Mock implements AppService {}
void main() {
final mockAppService = MockAppService();
when(mockAppService.getkIsWeb())
.thenAnswer((realInvocation) => true);
testWidgets("add item", (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(
title: Text("title"),
),
body: Center(
child: Text("message"),
),
),
));
final PaymentPageState myWidgetState = tester.state(find.byType(PaymentPage));
expect(find.byType(PaymentPage), findsOneWidget);
});
}
but I get the error
type 'Null' is not a subtype of type 'bool'
My AppService class and the abstract class looks like this,
abstract class IAppService {
bool getkIsWeb();
}
class AppService implements IAppService {
bool getkIsWeb() {
return kIsWeb;
}
}
I'm new to Flutter and does not know a lot of things. please help.
The solution you found about how to test kIsWeb
should work, but you have to understand the whole picture.
First of all, the main idea behind this approach is, to move the responsibility to decide, whether the application runs on the web or not, out of the widget and not use kIsWeb
directly in the widget's build method.
Therefore an interface named IAppService
is introduced and the class AppService
implements this interface. The interface is not really needed and I will work with the AppService
class directly in my example.
Your widget should use an instance of AppService
and call getKIsWeb
on it, instead of using the kIsWeb
constant directly. There are many ways to provide the instance to the widget. Using a constructor parameter is one of the easiest, but you may want to take a look at dependency injection or state management solutions in the future.
class MyWidget extends StatelessWidget {
const MyWidget({Key? key, required this.appService}) : super(key: key);
final AppService appService;
@override
Widget build(BuildContext context) {
if (appService.getKIsWeb()) {
return const Text('I\'m web');
} else {
return const Text('I\'m not web');
}
}
}
class AppService {
bool getKIsWeb() {
return kIsWeb;
}
}
And last not least. When you test your widget, you give it a mocked implementation of the AppService
class, which returns either true or false when getKIsWeb
gets called, depending on what you want to test.
class MockAppService extends Mock implements AppService {}
void main() {
testWidgets('Test web widget', (WidgetTester tester) async {
final mockAppService = MockAppService();
when(() => mockAppService.getKIsWeb()).thenReturn(true);
await tester.pumpWidget(
MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: MyWidget(
appService: mockAppService,
),
),
),
);
final webTextFinder = find.text('I\'m web');
expect(webTextFinder, findsOneWidget);
});
testWidgets('Test not web widget', (WidgetTester tester) async {
final mockAppService = MockAppService();
when(() => mockAppService.getKIsWeb()).thenReturn(false);
await tester.pumpWidget(
MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: MyWidget(
appService: mockAppService,
),
),
),
);
final webTextFinder = find.text('I\'m not web');
expect(webTextFinder, findsOneWidget);
});
}
Please note that I am using Mocktail here instead of Mockito. But you should get the idea.
when(() => mockAppService.getKIsWeb()).thenReturn(false);
is Mocktails way to define the mocked behavior. https://pub.dev/packages/mocktail
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.