覆盖/模拟库函数以进行 dart/flutter 测试

Rob*_*ads 5 unit-testing dart flutter

我想知道是否有一种方法可以覆盖库函数,这样它们就不会触发或只返回其他内容。

import 'package:foo_package/exposing_foo_function.dart';

class TestableClass {
  bool bar() {
    return foo(); //foo is from the imported library
  }
}
Run Code Online (Sandbox Code Playgroud)

测试:

void main() {

  test('TestableClass.bar() when foo_package.foo() returns false', () {
    TestableClass testableClass = TestableClass();

    // Something to make foo_package.foo() return false.

    expect(testableClass.bar(), isFalse);

  });
}

Run Code Online (Sandbox Code Playgroud)

jam*_*lin 3

诸如mockito通过创建实现模拟类接口的模拟类来工作。然而,这不适用于全局函数和静态函数。

相反,您可以做的是避免直接调用这些全局/静态函数,而是通过额外的间接级别调用它们。例如:

import 'package:foo_package/exposing_foo_function.dart' as foo_package;

class TestableClass {
  final bool Function() foo;

  TestableClass({this.foo = foo_package.foo});

  bool bar() {
    return foo();
  }
}
Run Code Online (Sandbox Code Playgroud)

然后测试:

void main() {
  test('TestableClass.bar() when foo_package.foo() returns false', () {
    bool fakeFoo() => false;
    TestableClass testableClass = TestableClass(foo: fakeFoo);
    expect(testableClass.bar(), isFalse);
  });
}
Run Code Online (Sandbox Code Playgroud)

类似的方法是将全局/静态函数包装为类的实例方法:

import 'package:foo_package/exposing_foo_function.dart' as foo_package;

class FooManager {
  bool foo() => foo_package.foo();
}

var fooManager = FooManager();

class TestableClass {
  bool bar() {
    return fooManager.foo();
  }
}
Run Code Online (Sandbox Code Playgroud)

然后您的测试可以FooManager像任何其他类一样进行模拟并设置fooManager为模拟版本。(或者,如果您更喜欢全局变量的依赖反转,请将您的模拟版本传递FooManagerTestableClass构造参数。)

当然,以上所有内容仅对您自己通过包装器的调用有帮助。如果您无法控制的代码调用这些函数,那将无济于事。在这种情况下,您最好的做法可能是向函数的作者抱怨缺乏可测试性。