4

我正在研究制作一个DataContext可以在单元测试中使用的可模拟对象。这里描述了一种方法。但是,这种方法的问题在于,对存储库的更改会立即生效——在调用Commit(或任何其他等效于)之前。SubmitChanges

另一方面,包含正确的SubmitChanges行为将涉及从 复制大量复杂代码DataContext,并可能导致更多错误。

模拟内存存储库(不等待SubmitChanges)的天真实现对于使用单元测试是否可行?这通常是如何完成的?

4

3 回答 3

4

如果我的理解是正确的,那么您还没有完全确定您的 SUT(被测对象)。

  • 如果您想测试与数据库的连接性,那么我们正在谈论集成测试,您不应该模拟您的DataContext

  • 如果你想测试调用的逻辑DataContext那么它是一个单元测试

无论如何,我建议您将调用包装DataContext在存储库中,存储库将负责数据库通信,遵循这种方法将使您更轻松

我会用一个例子来说明它,最后我会推荐几个链接来帮助你编写可测试的代码。(我总是这么说,我会再说一遍,写测试很容易,真正的努力必须放在写干净的可测试代码上)

public interface IMyRepository
{
   void ChangeEmail(int employeeId, string newEmail);
}
public class MyRepository : IMyRepository
{
   private MyDataContext context;
   public MyRepository(MyDataContext context)
   {
      this.context = context;
   }
   public void ChangeEmail(int employeeId, string newEmail)
   {
      //save your email using your context
   }
}

现在在您的消费者代码中,您将注入您的存储库:

public class MyCommand
{
   public MyCommand(IMyRepository myRepository)
   ...
   public void ChangeEmail(int employeeId, string newEmail)
   {
      //adding condition just to clarify how to test
      if(this.AllowChangeEmail(employeeId))
      {
         this.myRepository.ChangeEmail(employeeId, newEmail);
      }
      else
      {
         throw new DomainException("this should not happen");
      }
   }
   ...
}

我们已经解耦了 的使用DataContext,从您的域代码的角度来看,DataContext不存在,域知道的唯一代码是IMyRepository并且因为它是一个接口,您可以轻松更改提供者更改应用程序的行为,而无需重构您的域代码

如果你注意到我还没有谈到测试,为什么?因为就像我说的,首先要做的是编写干净的可测试代码(不要误解,应该遵循 TDD,这意味着应该先编写测试,我遵循这种方法只是为了演示)现在我们有了这段代码,我们看看测试应用程序逻辑IMyRepository有多容易

public class MyFakeProvider : IMyRepository
{
   public void ChangeEmail(int employeeId, string newEmail)
   {
      //write some assert here indicating the method was called
   }
}

[Test]
public void MyTest()
{
   var myMock = new MyFakeProvider();
   var sut = new MyCommand(myMock);

   sut.Invoking(x => x.ChangeEmail(3, "my@email.com")).ShouldNotThrow();
}

这些链接只关注一件事:编写可测试的代码:

http://misko.hevery.com/code-reviewers-guide/

http://misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf

http://misko.hevery.com/presentations/

http://www.youtube.com/watch?v=wEhu57pih5w&feature=player_embedded

http://www.youtube.com/watch?v=RlfLCWKxHJ0&feature=player_embedded

http://www.youtube.com/watch?v=-FRm3VPhseI&feature=player_embedded

http://www.youtube.com/watch?v=4F72VULWFvc&feature=player_embedded

于 2012-04-30T04:02:55.970 回答
2

被测试的类/组件是什么?如果您不直接测试存储库而只测试正在使用存储库的东西,那么模拟可以根据您的需要进行。

但是,如果您想在组件和存储库之间执行端到端集成测试,则需要另一种方法,例如。针对测试数据库运行。

于 2012-04-30T01:55:08.013 回答
1

我创建了一个接口来表示存储库,其中有 SubmitChanges、InsertOnSubmit 等 DataContext 实现的东西。此外,您的表的 IQueryable 属性。然后,您的 DataContext 子类可以实现此接口,您无需执行任何操作。对于您的单元测试,您可以只创建一个模拟,并模仿 IQueryables 您可以创建列表并使用 AsQueryable 方法。

于 2012-04-30T02:09:41.557 回答