2013-12-09 40 views
0

无可否认,这是一个奇怪的测试案例,但这是我遇到的一个问题。我有一个在其构造函数中将函数作为参数的类。我想知道是否传入的函数被调用。这里有一个例子: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接受一个函数作为参数,并调用它。如果您要传入(实例实例类).myNamedFunction,则会反过来在RealClass上调用专用函数_theNamedFunction。但是,如果您尝试模拟RealClass并将所有调用从myNamedFunction重定向到RealClass myNamedFunction,则这似乎失败。我没有看到任何明确的方法来实现这个目标,但我认为这是可能的。

任何想法?

回答

2

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

同时,Dart有非常好的嘲讽能力描述here(感谢@KWalrath的更新)。

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

嘲笑你的函数做到这一点:

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

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

当然的参数列表call将匹配,真正的功能。通过mock给您的间谍ClassThatCallsRealClass

+0

我不确定嘲笑函数实例的意思。我会怎么做呢? – mrand01

+0

编辑与东西给你考虑。 – Vidya

+0

第二段中的链接是一个非常古老的文章,因为它包含了一个过时的库,因此已被删除。也许看看mockito吧:https://pub.dartlang.org/packages/mockito –

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直接代替它需要一个调用。 调用是抽象的,所以我创建了一个实现。 MyFunc是一个包装函数的类。 MyFunc可以作为一个函数被调用,因为它实现了调用方法。

+0

这会修改ClassThatCallsRealClass中构造函数的方法签名,因此不幸的是我无法使用它。 – mrand01

+0

编辑了答案 –

相关问题