使用Dart进行模拟 - 如何测试作为参数传递的函数是否被调用?

时间:2013-12-09 18:10:03

标签: dart

不可否认,这是一个奇怪的测试案例,但这是我遇到的一个问题。我有一个类,它在一个构造函数中将函数作为参数。我想知道传递的函数是否被调用。这是一个例子:

class TestClassMock extends Mock implements RealClass {
  RealClass _real;

  TestClassMock() {
    _real = new RealClass();

    when(callsTo("myNamedFunction")).alwaysCall(_real.myNamedFunction);
  }
}

class RealClass {
  String _name = "RealClass";
  Function myNamedFunction;

  RealClass() {
    myNamedFunction = _theNamedFunction;
  }

  String _theNamedFunction() {
    return _name;
  }
}

class ClassThatCallsRealClass {
  ClassThatCallsRealClass(Function func) {
    func();
  }
}

//The test
TestClassMock testClassMock = new TestClassMock();
ClassThatCallsRealClass caller = new ClassThatCallsRealClass(testClassMock.myNamedFunction);  
testClassMock.getLogs(callsTo("myNamedFunction")).verify(happenedOnce);

所以为了解释一下,ClassThatCallsRealClass将一个函数作为参数并调用它。如果您要传入(Instance Of RealClass).myNamedFunction,则会依次调用RealClass上的私有函数_theNamedFunction。但是,如果您尝试模拟RealClass并将myNamedFunction中的所有调用重定向到RealClass myNamedFunction,则这似乎失败了。我没有看到任何明确的方法来实现这一点,但我认为这是可能的。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

在Dart中,所有函数都是类Function的实例,因为您将Function的实例传递给ClassThatCallsRealClass构造函数。 Function的实例有一个方法call(),如here所示。

与此同时,Dart具有非常好的模拟功能here(感谢@KWalrath的更新)。

所以你需要做的就是测试与其他任何对象一样的模拟。正如引用中所述,为ClassThatCallsRealClass创建一个间谍,为Function实例创建一个模拟。然后在函数的verify(happenedOnce)方法上使用call()

要模拟你的功能,请执行以下操作:

class MockFunction extends Mock {
  call(int a, int b) => a + b;
}

var mock = new MockFunction();
mock(1,2); //returns 3

当然,call的参数列表将匹配实际函数的参数列表。在mock上将ClassThatCallsRealClass传递给您的间谍。

答案 1 :(得分:1)

这对我有用:

library x;

import "package:unittest/unittest.dart";
import "package:unittest/mock.dart";

class TestClassMock extends Mock implements RealClass {
  RealClass _real;

  TestClassMock() {
    _real = new RealClass();

    when(callsTo("myNamedFunction")).alwaysCall(_real.myNamedFunction);
  }
}

class RealClass {
  String _name = "RealClass";
  Function myNamedFunction;

  RealClass() {
    myNamedFunction = _theNamedFunction;
  }

  String _theNamedFunction() {
    return _name;
  }
}

class ClassThatCallsRealClass {
  ClassThatCallsRealClass(Function func) {
    func();
  }
}

class MyFunc implements Function {

  Function func;
  String functionName;

  MyFunc(this.func, this.functionName);

  call() {
    var inv = new MyInvocation(functionName);
    func(inv);
  }
}

main(List<String> args) {
  test('xx', () {
    //The test
    TestClassMock testClassMock = new TestClassMock();
    ClassThatCallsRealClass caller = new ClassThatCallsRealClass(new MyFunc(testClassMock.noSuchMethod, "myNamedFunction"));  
    testClassMock.getLogs(callsTo("myNamedFunction")).verify(happenedOnce);
  });
}

class MyInvocation extends Invocation {
  final String f;
  MyInvocation(this.f); 

  bool get isGetter => false;

  bool get isMethod => true;

  bool get isSetter => false;

  Symbol get memberName => new Symbol(f);

  Map<Symbol, dynamic> get namedArguments => {};

  List get positionalArguments => [];
}

testClassMock.myNamedFunction返回null,所以我直接调用noSuchMethod,而这需要一个Invocation。 调用是抽象的,所以我创建了一个实现。 MyFunc是一个包装函数的类。 MyFunc可以作为函数调用,因为它实现了调用方法。