2014-08-27 64 views
1

我有一些問題試圖使用RhinoMocks來弄清楚,如果在被測試的類中調用方法,也會調用其他一些方法。被測試 我的類:Rhinomocks:我不能正確使用AssertWasCalled

public class OrderMessageHandler : IHandleMessages<UpdateOrder> 
{ 

    public virtual IRepository Repository { get; set; } 

    public void Handle(UpdateOrder message) 
    { 
     if (!message.Order.Confirmed) return; 
     using (var om = new OperationManager()) 
     { 
      try 
      { 
       om.BeginOperation(); 
       LVR.Order.Model.OrderHeader order = ConvertToLocalOrderHeader(message.Order); 
       Repository.SaveUpdate(order); 
       om.CommitOperation(); 
      } 
      catch (Exception ex) 
      { 
       om.RollbackOperation(); 
       // other stuff here 
      } 
     } 
    } 

    internal virtual LVR.Order.Model.OrderHeader ConvertToLocalOrderHeader(Protocol.DTO.OrderHeader order) 
    { 
     // do stuff here, and call Repository.GetAll<Country>() 
    } 
} 

這裏是我的測試方法

[Fact] 
public void ConvertToLocalOrderHeader_GivenConfirmedOrderMessage_CallTheConversionMethods() 
{ 
    // create a partial mock 'cause I want some of the implementation to be the true sut class 
    var sut = MockRepository.GeneratePartialMock<OrderMessageHandler>(); 
    // create a stub for the repository, in order to avoid hitting the db 
    sut.Repository = MockRepository.GenerateStub<IRepository>(); 
    sut.Repository.Stub(r => r.GetAll<Country>()) 
     .Return(
      new List<Country> 
       { 
        new Country {CountryID = "IT", Description = "Italy"}, 
        new Country {CountryID = "US", Description = "United States"} 
       }.AsQueryable() 
    ); 
    sut.Repository.Stub(r => r.SaveUpdate<OrderHeader>(Arg<OrderHeader>.Is.Anything)); 

    // call the method I want to test 
    sut.Handle(new UpdateOrder 
     { 
      Order = order, 
      EventId = new Guid(), 
      EventTime = DateTime.Now 
     }); 

    // verify that the method has been called (this is useless in my real test, I put it here just to understand why it doesn't work) 
    sut.AssertWasCalled(s => s.Handle(Arg<UpdateOrder>.Is.Anything)); 
    // verify that an inner method (virtual) has been called during the execution of sut.handle() 
    sut.AssertWasCalled(s => s.ConvertToLocalOrderHeader(order));      
} 

在2個sut.AssertWasCalled電話,我收到一個錯誤對象引用不設置到對象的實例。 。其原因是,sut.AssertWasCalled作出的方法我正在驗證一個電話......這樣

sut.AssertWasCalled(s => s.Handle(Arg<UpdateOrder>.Is.Anything)); 

電話

sut.Handle(null) 

而且是空的方法拋出一個異常的參數。 問題太糟糕了,它不應該重新調用這個方法,而只是告訴我它在測試方法之前是否從未被調用過。 這裏有什麼問題?

編輯:

按在收到的意見建議,我嘗試了不同的方法(因爲我不喜歡的期望/驗證味)。這裏的測試方法:

[Fact] 
public void ConvertToLocalOrderHeader_GivenConfirmedOrderMessage_CallTheConversionMethods2() 
{ 
    var mocks = new MockRepository(); 
    var sut = mocks.PartialMock<OrderMessageHandler>(); 
    sut.Repository = mocks.Stub<IRepository>(); 
    sut.Repository.Stub(r => r.GetAll<Country>()) 
      .Return(
       new List<Country> 
        { 
         new Country {CountryID = "IT", Description = "Italy"}, 
         new Country {CountryID = "US", Description = "United States"} 
        }.AsQueryable() 
     ); 
    sut.Repository.Stub(r => r.SaveUpdate<OrderHeader>(Arg<OrderHeader>.Is.Anything)); 
    Expect.Call(() => sut.Handle(Arg<UpdateOrder>.Is.Anything)); 
    sut.Replay(); 
    sut.Handle(new UpdateOrder 
     { 
      Order = order, 
      EventId = new Guid(), 
      EventTime = DateTime.Now 
     }); 
    mocks.VerifyAll();  
} 

ADN這裏是我的錯誤:

System.InvalidOperationException 
Previous method 'OrderMessageHandler.get_Repository();' requires a return value or an exception to throw. 

錯誤是由代碼行,即使這種方法拋出

Expect.Call(() => sut.Handle(Arg<UpdateOrder>.Is.Anything)); 

所以,沒有運氣...

還有其他想法嗎?

+0

您可以嘗試使Handle方法爲虛擬嗎?除非你這樣做,否則我認爲犀牛不能在這種情況下重寫該方法。 – 2014-08-27 14:53:26

+0

mh,你是對的......太糟糕了總體行爲沒有任何變化:我仍然有同樣的問題 – themarcuz 2014-08-27 15:08:00

+0

我想在你的情況下使用Excpect,就像這個例子http://ayende.com/wiki/Rhino+Mocks + Partial + Mocks.ashx?AspxAutoDetectCookieSupport = 1 – 2014-08-27 15:27:41

回答

3

我發現問題所在:方法ConvertToLocalOrderHeader應該聲明至少protected internal爲了讓Rhinomocks重寫它。是不夠的,作爲一個不同類的測試類。 非常簡單的解決方案,需要花費數小時才能解決的問題:/