[英]Unit testing in Flutter passing BuildContext
I have a method in a Dart class, which accepts BuildContext
parameter, as follows:我在 Dart 类中有一个方法,它接受
BuildContext
参数,如下所示:
class MyClass {
<return_type> myMethodName(BuildContext context, ...) {
...
doSomething
return something;
}
}
I want to test that the method works as expected:我想测试该方法是否按预期工作:
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
...
void main() {
MyClass sut;
setUp(() {
sut = MyClass();
});
test('me testing', () {
var actual = sut.myMethodName(...);
expect(actual, something);
});
}
Of course, it won't work, because the method myMethodName
needs a parameter BuildContext
type.当然不行,因为方法
myMethodName
需要一个参数BuildContext
类型。 This value is available throughout the application itself, but not sure where to get that from in my unit tests.该值在整个应用程序本身中都可用,但不确定在我的单元测试中从何处获取该值。
One way is to use testWidgets
in combination with a Builder
widget :一种方法是将
testWidgets
与Builder
小部件结合使用:
testWidgets('me testing', (WidgetTester tester) async {
await tester.pumpWidget(
Builder(
builder: (BuildContext context) {
var actual = sut.myMethodName(context, ...);
expect(actual, something);
// The builder function must return a widget.
return Placeholder();
},
),
);
});
You can actually mock the BuildContext
so the test will run headless.您实际上可以模拟
BuildContext
以便测试将无头运行。 I think it's better but might be not a solution that you are looking for.我认为它更好,但可能不是您正在寻找的解决方案。
BuildContext
is an abstract class therefore it cannot be instantiated. BuildContext
是一个抽象类,因此它不能被实例化。 Any abstract class can be mocked by creating implementations of that class.任何抽象类都可以通过创建该类的实现来模拟。 If I take your example then the code will look like this:
如果我以你的例子为例,那么代码将如下所示:
class MockBuildContext extends Mock implements BuildContext {}
void main() {
MyClass sut;
MockBuildContext _mockContext;
setUp(() {
sut = MyClass();
_mockContext = MockBuildContext();
});
test('me testing', () {
var actual = sut.myMethodName(_mockContext, ...);
expect(actual, something);
});
}
Here is a simple way to retrieve a BuildContext instance inside a test case:这是在测试用例中检索 BuildContext 实例的一种简单方法:
testWidgets('showDialog', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(home: Material(child: Container())));
final BuildContext context = tester.element(find.byType(Container));
final dialog = showDialog(
context: context,
builder: (context) => AlertDialog(
content: Text('shown by showDialog'),
),
);
// apply your tests to dialog or its contents here.
});
This was inspired by Simple dialog control test from the Flutter test cases for the showDialog()
function.这是受 Flutter 测试用例中
showDialog()
函数的Simple dialog control test 的启发。
The whole "app" consist of a Container
widget in a MaterialApp
frame.整个“应用程序”由
MaterialApp
框架中的Container
小部件组成。 The BuildContext
instance is retrieved form by finding the Element
instance related to the Container
. BuildContext
实例是通过查找与Container
相关的Element
实例来检索的。
I am totally fine with 'surga' answer, but in some cases, it won't be good enough.我对“surga”的回答完全没问题,但在某些情况下,这还不够好。 like when you want to use this
BuildContext
with InhiretedWidget
for example: Provider
or MediaQuery
.就像当您想将此
BuildContext
与InhiretedWidget
一起使用时,例如: Provider
或MediaQuery
。
So I suggest using the Mockito
default generator to generate the BuildContext
class for you.所以我建议使用
Mockito
默认生成器为你生成BuildContext
类。
@GenerateMocks([BuildContext])
BuildContext _createContext(){
final context = MockBuildContext();
...
And add build_runner
to your pubspec.yaml
并将
build_runner
添加到您的pubspec.yaml
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: any //use any version you want
Then run this command:然后运行这个命令:
flutter packages pub run build_runner build
Now you can create a context
object from the MockBuildContext
class as it is created normally from the MaterialApp
.现在您可以从
MockBuildContext
类创建context
对象,因为它通常是从MaterialApp
创建的。
@GenerateMocks([BuildContext])
BuildContext _createContext(){
final context = MockBuildContext();
final mediaQuery = MediaQuery(
data: MediaQueryData(),
child: const SizedBox(),
);
when(context.widget).thenReturn(const SizedBox());
when(context.findAncestorWidgetOfExactType()).thenReturn(mediaQuery);
when(context.dependOnInheritedWidgetOfExactType<MediaQuery>())
.thenReturn(mediaQuery);
return context;
}
Note: It's not required to add when..thenReturn
's for this Mock, it is depends on your needs.注意:不需要为这个 Mock 添加
when..thenReturn
,这取决于您的需求。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.