用Dart Mockito嘲笑扩展方法?

qltillow  于 2023-03-12  发布在  其他
关注(0)|答案(2)|浏览(151)

是否可以在Dart中使用mockito插件模拟或伪造一个需要用其他类扩展的类?
我有以下继承的例子:

abstract class Animal {
  Animal(this.emoji);

  final String emoji;

  String greet();
}

class Dog extends Animal {
  Dog(super.emoji);

  @override
  String greet() {
    return '$emoji: Woof!';
  }
}

class Poodle extends Dog {
  Poodle(super.emoji);
}

class FakePoodle extends Fake implements Poodle {
  // Raises a runtime error:
  // Runtime error: No associated positional super constructor parameter.
  FakePoodle(super.emoji);
}

我想模拟类FakePoodle,它仍然会继承类Dog的所有属性,使用构造函数,并使它与mockito同时为假。
以下是我的测试:

import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';

void main() {
  group('Dog tests', () {
    test('should return a dog greet', () {
      expect(Dog('🐶').greet(), '🐶: Woof!');
    });

    test('Poodle should return a poodle greet', () {
      expect(Poodle('🐩').greet(), '🐩: Woof!');
    });

    test('Fake Poodle should greet only once', () {
      final FakePoodle fakePoodle = FakePoodle('🐕‍');
      fakePoodle.greet();
      verify(fakePoodle.greet());
    });
  });
}

我从mockito插件中找到了以下常见问题部分:

如何模拟扩展方法?

如果没有办法覆盖某种函数,那么mockito就不能模拟它。有关进一步的解释和替代方法,请参见上面的答案。
有没有一种方法可以让我以一种干净的方式编写这样的集成测试?

wfveoks0

wfveoks01#

首先,a fake is different from a mock.Mock用于验证行为。(具体来说,它们用于验证 * 其他 * 对象与被模拟对象交互的行为。被模拟对象 * 不是 * 正在测试的对象。)您不能在Fake上使用verify
如果您希望FakePoodle成为Fake,但要重用Poodle中的一些实现,则可以执行以下操作:

class FakePoodle extends Fake implements Poodle {
  Poodle _realPoodle;

  FakePoodle(String emoji) : _realPoodle(emoji);

  @override
  String greet() => _realPoodle.greet();
}

但不清楚为什么要这样做,而不是仅仅使用实际的Poodle示例(除非Poodle上有其他方法,如果调用这些方法,您希望它们抛出UnimplementedError)。
您可能需要一个 mock 来代替,因为您想使用verify。同样,它们被用来验证其他被测试对象的行为,因此模拟对象的实现通常不重要,希望模拟对象从基类继承一些实现与这种理念相冲突。
但是如果你仍然想要一个mock,但是仍然想要重用实现(也许那个实现特别复杂,并且确定一个预先计算的stubbed响应是很重要的,或者也许那个实现有重要的副作用),那么你可以用调用真实的对象的stub来做一个Mock Package 器:

test('Fake Poodle should greet only once', () {
      var poodle = Poodle('🐕‍');
      var mockPoodle = MockPoodle();
      when(mockPoodle.greet()).thenAnswer((_) => poodle.greet());
      mockPoodle.greet();
      verify(mockPoodle.greet());
    });

最后,我会指出,如果MockFake不符合您的要求,您不必使用它们。也就是说,您还可以手动执行以下操作:

class TrackedPoodle extends Poodle {
  int greetCallCount = 0;

  TrackedPoodle(super.emoji);

  @override
  String greet() {
    greetCallCount += 1;
    return super.greet();
  }
}

顺便说一句,你的其他术语到处都是。“Extension methods“是完全不相关的。另外,“integration tests“是整体测试;他们通常不应该使用mock或fakes。mock和fakes通常被用来测试程序的一部分。

n53p2ov0

n53p2ov02#

你可以创建一个新类MockPoodle来扩展Poodle并覆盖greet()方法:

class MockPoodle extends Poodle {
  MockPoodle(String emoji) : super(emoji);

  @override
  String greet() {
    return 'Mock Poodle: Woof!';
  }
}

然后可以使用Mockito创建MockPoodle类的模拟对象,并验证是否调用了其greet()方法:

test('Mock Poodle should greet only once', () {
  final mockPoodle = MockPoodle('🐕‍');
  mockPoodle.greet();
  verify(mockPoodle.greet());
});

相关问题