2013-11-27 39 views
1

的我有一個類類同此:斷言無效異步方法

public class MyClass 
{ 
    public Task MyMethod() 
    { 
     //do something 
    } 
} 

如上所述,「myMethod的」是異步的,可以說,爲簡單起見,這是它的實現:

public Task MyMethod() 
    { 
     return Task.Run(() => 
     { 
      var success = _someService.DoSomething(); 
      if (!success) throw new Exception("unsuccsesfull"); 
     }); 

    } 

顯然,當MyMethod等待回調將運行時,這意味着在運行線程中不會拋出異常,這意味着「MyMethod」調用是成功的。

我想測試這種方法。測試方法如下:

[Test] 
public async void TestMyMethod_TestInitialState_TestExpectedResult() 
{ 
    // test initialization.. 
    //... 
    //.. 
    var myClass = new MyClass(); 
    await myClass.MyMethod(); 

    Assert.That(????) 
} 

我的問題 - 什麼是正確的斷言?

我有一個可能的解決方案 - 邏輯成員添加到「MyClass的」和根據該方法的結果更新這構件:

public class MyClass 
{ 
    public bool SomeMember { get; private set; } 

    public Task MyMethod() 
    { 
     Task.Run(() => 
     {    
      SomeMember = _someService.DoSomething(); 
      if (!SomeMember) throw new Exception("unsuccsesfull"); 
     }); 

    } 
} 

這樣我可以斷言這樣的試驗:

[Test] 
    public async void TestMyMethod_TestInitialState_SomeMemberShouldBeTrue() 
    { 
     // test initialization.. 
     //... 
     //.. 
     var myClass = new MyClass(); 
     await myClass.MyMethod(); 

     Assert.True(SomeMember) 
    } 
} 

但是,我不喜歡這個解決方案,因爲我爲'MyClass'添加一個屬性只是爲了能夠聲明一個測試,我真的不需要這個屬性在我的業務世界。此外,每個添加到類中的屬性都代表該類的某些狀態,並增加了一個comlexity級別。

對此提出建議?

蓋伊。

+0

那麼想必異步操作也有一定效果 - 否則將是毫無意義的執行它。它在做什麼,你可以測試它發生了什麼? –

+0

在我的情況下,它發送另一臺計算機的文件。這是通過交換通信消息並使用從其請求文件的另一臺機器的TFTP服務器完成的。我將通過從該機器收到的通信消息瞭解該過程的成功,表明該文件處於其會話中。我不控制這個通知消息何時到達,因此我所提供的異步接口 –

+0

那麼它在你的測試環境中做了什麼?據推測,它實際上並沒有在這種情況下做TFTP ... –

回答

3

你想要什麼叫做「模擬」或「存根」。這個想法是,你重構你的代碼,以便它具有對接口的依賴,然後在測試時模擬接口。

有各種框架/工具可以幫助模擬(Moq,Microsoft Fakes,TypeMock Isolator,JustMock等),還有很多框架可以幫助解決依賴注入(Unity,Castle Windsor,StructureMap,Autofac等)。

但是你可以自己開始做。首先,重構MyClass所以這取決於ISomeService

public interface ISomeService 
{ 
    bool DoSomething(); 
} 

public class MyClass 
{ 
    private readonly ISomeService _someService; 

    public MyClass(ISomeService someService) 
    { 
    _someService = someService; 
    } 

    public Task MyMethod() 
    { 
    return Task.Run(() => 
    { 
     var success = _someService.DoSomething(); 
     if (!success) throw new Exception("unsuccsesfull"); 
    }); 
    } 
} 

然後在您的單元測試:

private class TestService : ISomeService 
{ 
    public bool DoSomethingReturnValue { get; set; } 

    public bool DoSomething() { return DoSomethingReturnValue; } 
} 

[Test] 
public async Task TestMyMethod_TestInitialState_TestExpectedResult() 
{ 
    var myClass = new MyClass(new TestService { DoSomethingReturnValue = true }); 
    await myClass.MyMethod(); 
} 

[Test] 
public async Task TestMyMethod_TestInitialState_TestFailure() 
{ 
    var myClass = new MyClass(new TestService { DoSomethingReturnValue = false }); 
    Assert.Throws(() => myClass.MyMethod()); // (I'm unsure of the exact NUnit syntax) 
} 
+0

althoug我沒有問過關於嘲笑我認爲你的答案符合我的reqiuerments ..謝謝! –