2010-05-28 123 views
0

我有一個服務代理類,使asyn調用服務操作。我使用回調方法將結果傳回給我的視圖模型。RhinoMocks測試回調方法

做視圖模型的功能測試,我可以嘲笑服務代理,以確保在代理上調用方法,但我怎樣才能確保調用回調方法呢?

隨着RhinoMocks我可以測試事件處理和模擬對象上的事件引發事件,但我怎麼測試回調?

視圖模型:

public class MyViewModel 
{ 
    public void GetDataAsync() 
    { 
     // Use DI framework to get the object 
     IMyServiceClient myServiceClient = IoC.Resolve<IMyServiceClient>(); 
     myServiceClient.GetData(GetDataAsyncCallback); 
    } 

    private void GetDataAsyncCallback(Entity entity, ServiceError error) 
    { 
     // do something here... 
    } 

} 

ServiceProxy:

public class MyService : ClientBase<IMyService>, IMyServiceClient 
{ 
    // Constructor 
    public NertiAdminServiceClient(string endpointConfigurationName, string remoteAddress) 
     : 
      base(endpointConfigurationName, remoteAddress) 
    { 
    } 

    // IMyServiceClient member. 
    public void GetData(Action<Entity, ServiceError> callback) 
    { 
     Channel.BeginGetData(EndGetData, callback); 
    } 

    private void EndGetData(IAsyncResult result) 
    { 
     Action<Entity, ServiceError> callback = 
      result.AsyncState as Action<Entity, ServiceError>; 

     ServiceError error; 
     Entity results = Channel.EndGetData(out error, result); 

     if (callback != null) 
      callback(results, error); 
    } 
} 

感謝

回答

1

與此玩耍了一下,我想我可能知道你在找什麼。首先,我會展示我沒有驗證這個MSTest的代碼:

[TestClass] 
public class UnitTest3 
{ 
    private delegate void MakeCallbackDelegate(Action<Entity, ServiceError> callback); 

    [TestMethod] 
    public void CallbackIntoViewModel() 
    { 
     var service = MockRepository.GenerateStub<IMyServiceClient>(); 
     var model = new MyViewModel(service); 

     service.Stub(s => s.GetData(null)).Do(
      new MakeCallbackDelegate(c => model.GetDataCallback(new Entity(), new ServiceError()))); 
     model.GetDataAsync(null); 
    } 
} 

public class MyViewModel 
{ 
    private readonly IMyServiceClient client; 

    public MyViewModel(IMyServiceClient client) 
    { 
     this.client = client; 
    } 

    public virtual void GetDataAsync(Action<Entity, ServiceError> callback) 
    { 
     this.client.GetData(callback); 
    } 

    internal void GetDataCallback(Entity entity, ServiceError serviceError) 
    { 

    } 
} 

public interface IMyServiceClient 
{ 
    void GetData(Action<Entity, ServiceError> callback); 
} 

public class Entity 
{ 
} 

public class ServiceError 
{ 
} 

你會發現幾件事情:

  1. 我做你的回調內部。你需要使用InternalsVisisbleTo()屬性,這樣你的ViewModel程序集才能將內部結構暴露給你的單元測試(我對此並不瘋狂,但是在這種罕見的情況下會發生這種情況)。

  2. 我使用Rhino.Mocks「Do」在調用GetData時執行回調。它沒有使用提供的回調函數,但這實際上更像是一個集成測試。我假設你有一個ViewModel單元測試,以確保傳遞給GetData的真正回調在適當的時候執行。

  3. 很明顯,你會想創建模擬/存根實體和ServiceError對象,而不是像我一樣新建。

+0

請告訴我如何使內部方法可見單元測試項目。謝謝 – joblot 2010-06-01 05:53:56

+0

我已經制定了如何使內部方法可見。 能否請你解釋一下實際做了什麼以及爲什麼我們爲服務創建了一個螺柱。謝謝 – joblot 2010-06-01 06:04:08

+0

這只是你的ViewModel的單元測試。因此,所有外部依賴都被嘲弄/殘留。 「Do」方法告訴Rhino.Mocks在調用方法時執行特定的代碼片段。我使用了「Do」,這樣你的ViewModel就可以調用「GetDataAsync」並且還可以獲得回調 - 所有這些都在測試期間完成。 測試服務是否執行回調將作爲Service類的單元測試的一部分完成。 – PatrickSteele 2010-06-01 14:22:28