2012-10-31 48 views
3

我正在使用爲數據庫調用方法附帶IDatabase類的NPoco。我想驗證進入NPoco Insert方法的對象是否具有正確的數據(以域對象的形式)。如何在moq中調試驗證?

public interface IUnitOfWorkProvider 
    { 
     IUnitOfWork GetUnitOfWork(); 
    } 

    public interface IUnitOfWork : IDisposable 
     { 
      void Commit(); 
      IDatabase Db { get; } 
      void SetOneTimeCommandTimeout(int timeout); 
      void SetGlobalCommandTimeout(int timeout); 
     } 
    public interface IDatabase : IDatabaseQuery 
    { 
     IDbConnection Connection { get; } 
     IDbTransaction Transaction { get; } 

     void AbortTransaction(); 
     void BeginTransaction(); 
     void BeginTransaction(IsolationLevel? isolationLevel); 
     void CompleteTransaction(); 
     IDataParameter CreateParameter(); 
     int Delete(object poco); 
     int Delete<T>(object pocoOrPrimaryKey); 
     int Delete<T>(Sql sql); 
     int Delete<T>(string sql, params object[] args); 
     int Delete(string tableName, string primaryKeyName, object poco); 
     int Delete(string tableName, string primaryKeyName, object poco, object primaryKeyValue); 
     void Dispose(); 
     Transaction GetTransaction(); 
     Transaction GetTransaction(IsolationLevel? isolationLevel); 
     object Insert(object poco); 
     object Insert(string tableName, string primaryKeyName, object poco); 
     object Insert(string tableName, string primaryKeyName, bool autoIncrement, object poco); 
     void Save(object poco); 
     void Save(string tableName, string primaryKeyName, object poco); 
     IDatabase SetTransaction(IDbTransaction tran); 
     int Update(object poco); 
     int Update<T>(Sql sql); 
     int Update(object poco, IEnumerable<string> columns); 
     int Update(object poco, object primaryKeyValue); 
     int Update<T>(string sql, params object[] args); 
     int Update(object poco, object primaryKeyValue, IEnumerable<string> columns); 
     int Update(string tableName, string primaryKeyName, object poco); 
     int Update(string tableName, string primaryKeyName, object poco, IEnumerable<string> columns); 
     int Update(string tableName, string primaryKeyName, object poco, object primaryKeyValue); 
     int Update(string tableName, string primaryKeyName, object poco, object primaryKeyValue, IEnumerable<string> columns); 
    } 

// my test class file 
private IFixture fixture; 
    private Mock<IUnitOfWork> unitOfWork; 
    private MyService myService; 
    private Mock<IDatabase> database; // new based on responses 

    [SetUp] 
     public void Setup() 
     { 
      fixture = new Fixture().Customize(new AutoMoqCustomization()); 
database = fixture.Freeze<Mock<IDatabase>>();// new based on responses 
      unitOfWork = fixture.Freeze<Mock<IUnitOfWork>>(); 
      myService = fixture.CreateAnonymous<MyService>(); 
     } 

     [Test] 
     public MyTest() 
     {  
       // fails 
      unitOfWork.Setup(x => x.Db.Insert(It.IsAny<MyDomainObject>())); 
      myService.CallMyMethod(); 
      unitOfWork.Verify(x => x.Db.Insert(It.IsAny<MyDomainObject>())); 

      // fails 
      unitOfWork.Setup(x => x.Db.Insert(It.IsAny<object>())); 
      myService.CallMyMethod(); 
      unitOfWork.Verify(x => x.Db.Insert(It.IsAny<object>())); 
// fails (this was a try based on responses) 
database.Setup(x => x.Insert(It.IsAny<object>()));  
myService.CallMyMethod();   
database.Verify(x => x.Insert(It.IsAny<object>())); 

      // passes 
      unitOfWork.Setup(x => x.Db.Insert(It.IsAny<object>())); 
      myService.CallMyMethod(); 
      unitOfWork.Verify(); 
     } 

public class MyDomainObject 
{ 
    public void Id {get; set;} 
} 

的代碼被稱爲(我應該觸發驗證)

using (var unitOfWork = unitOfWorkProvider.GetUnitOfWork()) 
      { 
     MyDomainObject myDomain = anotherService.getMyDomain(DateTime.Now, 100); 
     unitOfWork.Db.Insert(myDomain); 

} 
+1

你的設置不從我所能看到的嘲笑 - 也就是說你可以做'x.Db',但是當你點到另一個關卡時,你不在Setup表達式可以做的事情上 - 這一點被'Verify( )'的作品[因爲你是呼號'x.Db']。但也許你已經剝去了太多。 –

+0

我會更新我的帖子。 – chobo2

+0

就像Ruben懷疑的那樣,'IDatabase Db'得到*自動模擬*,並且您對錯誤的對象設置了期望值。通常,在執行'x => x.Db ...'位('Db'爲空)時,您會得到空引用異常,但是由於您使用了AutoFixture,因此它會靜默地通過。你最後一個例子的作用只是因爲對'unitOfWork'完全沒有期望。我建議你'凍結''IDatabase'並設置它的期望值。 –

回答

2

的代碼在你的SUT使用一個IUnitOfWorkProvider生產IUnitOfWork:

using (var unitOfWork = unitOfWorkProvider.GetUnitOfWork()) 
{ 
    MyDomainObject myDomain = anotherService.getMyDomain(DateTime.Now, 100); 
    unitOfWork.Db.Insert(myDomain); 
} 

您當前正試圖模擬的IUnitOfWork實例是其他一些實例。它們不是由此IUnitOfWorkProvider生成的。

假設IUnitOfWorkProvider被注入到您的SUT中,您應該能夠凍結並從那裏開始。像這樣的東西應該工作:

var fixture = new Fixture().Customize(new AutoMoqCustomization()); 
var uowProviderStub = fixture.Freeze<Mock<IUnitOfWorkProvider>>(); 
var uowMock = fixture.CreateAnonymous<Mock<IUnitOfWork>>(); 
var sut = fixture.CreateAnonymous<MyService>(); 

uowProviderStub.Setup(p => p.GetUnitOfWork()).Returns(uowMock.Object); 
uowMock 
    .Setup(x => x.Db.Insert(It.IsAny<MyDomainObject>())) 
    .Verifiable(); 

// etc. 

這就是一個有點麻煩,這是真正的考驗要告訴你的是,Law of Demeter violation不是最好的設計......

+0

井(Expression'1表達,倍) 在Tests.Services.ServiceTests.Test()你如何避開迪米特本法?我的意思是說我的工作單位是如何設置的。 – chobo2

+0

爲了擺脫IUnitOfWorkProvider的你可以只直接注入IUnitOfWork到服務,並在您構成根管理服務和UOW的壽命。 –

+0

@ chobo2另一種方法是通過使用AutoFixture.xUnit和/或具有定製,做了'uowProviderStub.Setup(p值=> p.GetUnitOfWork())返回(uowMock.Object)掃地毯下的問題;'在幕後。但請不要做 - 馬克的妥善解決 –

0

你需要讓你的嘲笑電話覈實的

unitOfWork 
    .Setup(x => x.Db.Insert(It.IsAny<MyDomainObject>())) 
    .Verifiable(); 
+0

爲什麼?我嘗試過,但仍然失敗。我仍然得到Moq.MockException: 調用沒有在模擬上執行:x => x.Db.Insert(It.IsAny ()) – chobo2

+0

MockException還包含執行了什麼調用(如果有),你可以粘貼完整的異常在這打字? –

+0

Moq.MockException: 調用沒有在仿進行:X => x.Db.Insert(It.IsAny ()) 在Moq.Mock.ThrowVerifyException(IProxyCall預期,表達表達,倍) 在Moq.Mock。VerifyCalls(攔截targetInterceptor,MethodCall預期,表達表達,倍) 在Moq.Mock.Verify [T,TResult](模擬模擬,Expression'1表達,倍,字符串failMessage) 在Moq.Mock'1.Verify [TResult在管線393 – chobo2