2011-11-10 34 views
2

我有以下代碼:如何使用Rhino.Mocks模擬某些代碼?

public interface IFlowFolderHandler 
{ 
    OperationResult Post(FlowFolder dto); 
} 

public class FlowFolderHandler : IFlowFolderHandler 
{ 
    private readonly IResponse m_response; 
    private readonly IEntityRepository m_entityRepository; 

    public FlowFolderHandler(IResponse response, IEntityRepository entityRepository) 
    { 
    m_response = response; 
    m_entityRepository = entityRepository; 
    } 

    public OperationResult Post(FlowFolder dto) 
    { 
    var ent = FlowFolderX.Cast(dto, true); 
    m_entityRepository.Update(ent); 
    var id = EntityIdComparer.IdToString(ent.Id); 
    m_response.Headers["X-Entity-Id"] = id; 
    return new OperationResult.Created 
    { 
     RedirectLocation = new Uri("FlowFolder/" + id, UriKind.Relative), 
     ResponseResource = ent.GetEntityRelation(), 
    }; 
    } 
} 

我想單元測試FlowFolderHandler.Post方法,使用IResponseIEntityRepository嘲笑。我目前的實現是使用以下手冊嘲笑:

private class EntityRepositoryMock : IEntityRepository 
{ 
    private readonly Action<IEntityBase> m_update; 
    public EntityRepositoryMock(int id, EntityRelation entityRelation) 
    { 
    m_update = ent => EntityRepository.ApplySaveSideEffects(ent, id, entityRelation); 
    } 
    public IEntityBase Fetch(EntityId entityId) { throw new NotImplementedException(); } 
    public void FetchByExpression(Type entityType, Expression expr, IList list, List<Pair<string, bool>> orderBy) { throw new NotImplementedException(); } 
    public void Update(IEntityBase entity) { m_update(entity); } 
} 

private class ResponseMock : IResponse 
{ 
    public ResponseMock() { Headers = new HttpHeaderDictionary(); } 
    public IHttpEntity Entity { get { throw new NotImplementedException(); } } 
    public HttpHeaderDictionary Headers { get; private set; } 
    public void WriteHeaders() { throw new NotImplementedException(); } 
    public bool HeadersSent { get { throw new NotImplementedException(); } } 
    public int StatusCode 
    { 
    get { throw new NotImplementedException(); } 
    set { throw new NotImplementedException(); } 
    } 
} 

而且單元測試是:

[Test] 
[Factory("YieldPostFlowFolderData")] 
public void PostFlowFolder(int id, Uri uri, EntityRelation entityRelation, FlowFolder flowFolder) 
{ 
    var entityRepository = new EntityRepositoryMock(id, entityRelation); 
    var response = new ResponseMock(); 
    var handler = new FlowFolderHandler(response, entityRepository); 

    var result = handler.Post(flowFolder); 

    Assert.AreEqual((int)HttpStatusCode.Created, result.StatusCode); 
    Assert.AreEqual(id, int.Parse(response.Headers["X-Entity-Id"])); 
    Assert.AreEqual(uri, result.RedirectLocation); 
    SUC.Utils.AssertDeepEqual(entityRelation, result.ResponseResource); 
} 

我的問題是我怎麼能寫相同的單元測試(或多或少),無需進行手動嘲笑EntityRepositoryMockResponseMock使用Rhino.Mocks?

謝謝。

編輯

我手動嘲笑含有不僅因爲他們是手動嘲笑的構造函數。我本來可以添加一個專門的方法PrepareMock而不是構造函數來確保模擬已準備好......嘲笑。自動模擬,由Rhino.Mocks創建,不會有任何構造函數相關的問題,因爲我會模仿接口而不是具體類型。

回答

2

的使用expect(),你可以設置你想要的任何期望,例如EXP [ectation的更新()方法,它是唯一的一個做的事情,而不是拋出異常:

repositoryMock.Expect(m => m.Update(null)).IgnoreArguments.WhenCalled(
    mi => 
    { 
     IEntityBase passedInEntity = mi.Args[0] as IEntityBase; 
     EntityRepository.ApplySaveSideEffects(passedInEntity, id, entityRelation); 
    } 
).Repeat.Any(); 

同樣重要的一點是嘲諷的屬性,應指定PropertyBehaviour()

repositoryMock.Expect(m => m.Entity).Proeprtybehaviour(); 

編輯:要檢查方法被調用一次

repositoryMock.AssertWasCalled(m => m.Update(), mi => mi.Repeat.Once()); 

相關鏈接:

+0

我想實施你的意見。第一個問題 - Repeat.Many()的優點是什麼? – mark

+0

接下來,我試圖嘲笑響應。 'responseMock.Expect(m => m.Headers).PropertyBehavior();'不起作用,因爲'Headers'是一個只讀屬性。當'Headers' propery被調用時,我該如何告訴模擬返回某個對象? – mark

+0

對不起,'Repeat.Any()'。它表明指定的返回值應該被返回,即使方法被稱爲多次,你可以通過'Repeat.Once()'調用單個方法調用,所以每次下一次調用模擬方法將返回null而不是返回值返回類型不是void),這適用於'WhenCalled()',它將在每次調用方法時被執行,不僅僅是第一次 – sll

0

出於好奇,你的「手動」模擬會給你帶來麻煩,還是你只是在尋找一種更清晰的方式來實現它們?有時候,「手動」方式是最好的(最簡單的)方式,因爲大多數嘲笑框架都有自己的問題。

反正話說回來,以嘲諷類的基本步驟喜歡你這樣做:

  1. 創建MockRepository對象
  2. 問MockRepository對象來創建你的類/接口的模擬。有很多不同類型的模擬你可以要求(動態,部分,存根等等),你需要閱讀文檔來找出哪一個適合你。
  3. 用DO()處理有你的嘲笑執行您想要的(它看起來像這樣的代碼的特定位的是你在上面做什麼,特別是與EntityRepositoryMock.Update

的DO()處理程序這裏記載: http://ayende.com/wiki/Rhino+Mocks+The+Do()+Handler.ashx

你的模擬對象也有在構造函數代碼僅供參考,你可能會遇到一些問題,構造從Ayende:。

與嘲諷ç技術限制這是因爲模擬對象的類型 源自目標類,因此創建一個模擬對象調用目標類構造函數。

這是從這個頁面討論構造函數: http://ayende.com/wiki/Rhino+Mocks+Mocking+classes.ashx

+0

關於構造- 一世 編輯帖子。總的來說,你的迴應是RTFM的一種非常禮貌的形式,這是完全合法的,但我寧願準備好去做例子,我會從中找出其餘的。 – mark

+0

並不意味着遇到RTFM(雖然看着我的帖子,我想你是對的)。我不確定你的帖子是否曾經使用過Rhino.Mocks,所以我只是試圖給Do()處理程序一個大致的方向。看起來像sll有一個更具體的答案你.. – JohnD