如何在Flutter中测试一个方法并模拟同一类中的另一个方法



描述:我已经测试了methodA()methodB(),所以我可以确保它们被覆盖。通过模拟同一文件中的methodA()methodB()来测试methodToBeTested()的方法有哪些?参数通过methodToBeTested()传递到methodA()methodB(),以使用注入正确地测试这些方法。注意:它们不能被提取到不同的类,因为它是计算服务的相关逻辑,并且这些方法已经被原子分离。

代码:

class ClassForTesting {
int methodToBeTested(String a, String b) {
// Calculation in this method also is a bit more difficult
return methodA() + methodB();
} 
int methodA(String a) {
int value = 1;
// Here is calculation logic that has been tested
return value;
} 
int methodB(String b) {
int value = 2;
// Here is calculation logic that has been tested
return value;
} 
}

已经做了什么:我尝试了Mockito的几种方法,但它不允许这样做:

  1. @GenerateMocks-正在创建一个mock,并要求我使用when(),甚至methodToBeTested()来存根每个方法
  2. 通过使用下一个构造扩展Fake:
class Mock extends Fake implements PasswordValidatorService {}

但通过这种方式,我只继承了PasswordValidatorService's行为,而不是实现,并且每个未重写的方法都抛出UnimplementedError。因此,我无法覆盖methodToBeTested()并调用它的超级实现。

我发现Mockito for Java具有@Spy构造,在这种情况下这将是完美的,但不幸的是,它不适用于Dart和Flutter。

我目前唯一的方法是创建我自己的Mock:

class MockClassForTesting extends ClassForTesting {
@override
int methodA() {
return 2;
}
@override
int methodB() {
return 5;
}
}

但是这个实现不允许我使用Mockito对when()构造的灵活性,因为我必须有不同的methodA()methodB()返回。这一事实迫使我在MockClassForTesting中有额外的变量来实现when()构造功能。

问题:

  1. 实现我的目的的最佳方式是什么
  2. 在Widget测试期间可以使用相同的嘲讽方法吗

一种方法是使用混合方法,在该方法中创建自己的派生类,但其中一些重写委托给Mock实现。例如:

class ClassForTesting {
int methodToBeTested(String a, String b) {
// Calculation in this method also is a bit more difficult
return methodA(a) + methodB(b);
} 
int methodA(String a) {
int value = 1;
// Here is calculation logic that has been tested
return value;
} 
int methodB(String b) {
int value = 2;
// Here is calculation logic that has been tested
return value;
} 
}
class PartialMockClassForTesting extends ClassForTesting {
final mock = MockClassForTesting();
@override
int methodA(String a) => mock.methodA(a);
@override
int methodB(String b) => mock.methodB(b);
}
@GenerateMocks([ClassForTesting])
void main() {
test('Test partial mock', () {
var partialMock = PartialMockClassForTesting();
when(partialMock.methodA('hello')).thenReturn(42);
when(partialMock.methodA('goodbye')).thenReturn(-42);
when(partialMock.methodB('world')).thenReturn(10);
expect(partialMock.methodToBeTested('hello', 'world'), 52);
expect(partialMock.methodToBeTested('goodbye', 'world'), -32);
});
}

如果您想有条件地模拟某些方法,可以让您的重写检查布尔标志来有条件地调用mock或实际实现。例如:

class PartialMockClassForTesting extends ClassForTesting {
final mock = MockClassForTesting();
final shouldMock = <Function, bool>{};
@override
int methodA(String a) =>
shouldMock[methodA] ?? false ? mock.methodA(a) : super.methodA(a);
@override
int methodB(String b) =>
shouldMock[methodB] ?? false ? mock.methodB(b) : super.methodB(b);
}
@GenerateMocks([ClassForTesting])
void main() {
test('Test partial mock', () {
var partialMock = PartialMockClassForTesting();
partialMock.shouldMock[partialMock.methodA] = true;
partialMock.shouldMock[partialMock.methodB] = true;
...

最新更新