2013-12-09 78 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

編輯了答案 –

相關問題