c# - 在内存中模拟 LinqToSql 存储库以用于单元测试

标签 c# .net unit-testing linq-to-sql mocking

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

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

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

最佳答案

如果我的理解是正确的,那么你还没有完全确定你的 SUT (Subject Under Test)。

  • 如果你想测试与数据库的连接,那么我们正在谈论一个集成测试,你不应该模拟你的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
   }
}

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

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 并且由于它是一个接口(interface),您可以轻松更改提供者来更改应用程序的行为,而无需重构您的域代码

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

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

关于c# - 在内存中模拟 LinqToSql 存储库以用于单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10377135/

相关文章:

c# - 如何在最终生成的 pdf 文档中使用库 TheArtOfDev.HtmlRenderer.PdfSharp.PdfGenerator 下载嵌入式图像?

java - Mockito - 使用 Varargs 参数模拟重载方法

Angular - View 的代码覆盖率

c# - 为什么内部 .NET 方法比从 .NET 开源复制的简单代码快得多?

c# - 将 MongoDB 文档转换为对象的 c# 列表

c# - 命名空间 'Resources' 中不存在类型或命名空间名称 'MyProject.Properties'

.net - 使用异步 Socket.BeginReceive 时如何检测超时?

c# - INotifyDataErrorInfo.GetErrors 何时调用 null 与 String.empty?

javascript - 我如何在 Jasmine 中测试回调

c# - 如何从 AVISplitter 输出引脚获取音频到 C# 中的 MemoryStream?