2012-10-31 83 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