【问题标题】:How can I test a method and to mock another method that are in the same class in Flutter如何测试一个方法并模拟 Flutter 中同一类中的另一个方法
【发布时间】:2022-06-19 17:28:14
【问题描述】:

说明: 我已经测试了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 - 正在创建一个模拟,并要求我使用 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. 在小部件测试期间可以使用相同的模拟方法吗?

【问题讨论】:

  • 您可以创建自己的派生类,覆盖 methodAmethodB,并将这些特定的覆盖委托给 Mock 实现。
  • @jamesdlin 第一部分已经完成并在问题中描述,但第二部分我不明白。这是我在 Flutter 中进行单元测试的第一天。您的意思是对 MockClassForTesting 使用 GenerateMocks?
  • 我的意思是两件事都做:创建自己的派生类并像往常一样创建Mock,然后使用混合方法,派生类使用Mock 来获取特定方法。

标签: flutter android-studio unit-testing dart mockito


【解决方案1】:

一种方法是使用混合方法,您可以创建自己的派生类,但其中的一些覆盖委托给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);
  });
}

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

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;
    ...

【讨论】:

  • 这是一个很好的答案,但这样我不能将任何匹配器作为参数传递给 methodA。你知道如何让这成为可能吗?
  • @DenFav 如果需要,您可以随时使用partialMock.mock.methodA(argumentMatcher),或者您可以使PartialMock 的覆盖使用dynamic 类型的参数。
  • 感谢它的工作。关于这个还有一个问题。该类包含方法methodToBeTested,A,B,C。methodToBeTested调用A和B,B调用C。通过模拟A和B,我可以测试methodToBeTested,但如果我模拟C,我无法测试B,因为B被模拟并且需要存根除了功能。我试图存根 B 来调用真正的实现,但我无法在 thenAnswer 闭包中调用该方法的父实现。有没有办法做到这一点,或者我需要创建另一个自定义模拟类?谢谢!
  • @DenFav 我已经用一种方法更新了我的答案,该方法应该比为要模拟的每种方法组合创建自定义类的工作量更少。
猜你喜欢
  • 1970-01-01
  • 2014-07-20
  • 1970-01-01
  • 2020-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多