单元测试交叉层边界

时间:2015-12-10 21:19:06

标签: c# unit-testing service-layer

我有一个单元测试,我在其中测试我的Service类在各种条件下将数据插入到我的Repository类中的正确位置。我的存储库类有三个"存储"位置,我的Service类有一个公共AddData方法,它有条件地将数据添加到存储库中的三个存储之一(生产中的不同数据库表集)之一。是否可以让我的单元测试查看服务的存储库以确保数据添加到正确的位置?例如:

服务类如下所示:

class MyService
{
   private readonly IRepository Repository;       

   // Add data to a different place in the repository based on the value of the 'someSwitch' parameter
   public void AddData(MyDataObject data, int someSwitch)
   {   
      if (someSwitch >= 0 && someSwitch < 10)
      { 
         this.Repository.AddToStorageOne(data);
      }
      else if (someSwitch >= 10 && someSwitch < 20)
      {
         this.Repository.AddToStorageTwo(data);
      }
      else
      {
         this.Repository.AddToStorageThree(data);
      }
   }
}

单元测试如下:

[TestClass]
public class MyTests
{
   [TestMethod]
   private void AddData_SwitchValueOf15_ShouldAddToStorageTwo()
   {
      // Create the MyService class with an in-memory repository
      MockRepository repository = new MockRepository();
      MyService service = new MyService
      {
         Repository = repository
      };

      MyDataObject myDataObject = new MyDataObject();
      // Assign some data to myDataObject

      // This should insert myDataObject into StorageTwo
      service.AddData(myDataObject, 15);

      // Here I want to assert that the data got added to "StorageTwo" in the repository
   }
}

现在我想测试数据是否已插入到存储库的StorageTwo中。当然,我很容易做一些像

这样的事情
Assert.AreEqual(0, repository.StorageOne.Count);
Assert.AreEqual(1, repository.StorageTwo.Count);
Assert.AreEqual(0, repository.StorageThree.Count);

所以我的问题是,我的单元测试(测试服务方法)是否可以像这样查看服务的存储库?如果这样做是不好的做法,我该如何检查数据是否已插入存储库中的正确位置?我的服务类只有一个公共GetData()方法,它结合了StorageOneStorageTwoStorageThree的数据,因此服务类没有任何公开可以查看单个存储的方法。

1 个答案:

答案 0 :(得分:2)

在单元测试中,你不应该超越你班级的界限。一种方法是模拟每个依赖项。一旦他们被嘲笑,您就可以验证您的班级与外界的互动。

这也有助于减少仅为测试编写的代码。例如,您必须在场景中公开存储的Count以进行测试。如果你盲目地相信回购做它的工作(因为它也应该进行单元测试)并且检查你是否正确地调用它是没有必要的。

在您的特定情况下,您可以模拟您的Repository,然后断言调用了正确的方法。作为一种额外的安全措施,您可以验证其他人不是。

使用Moq,它看起来像这样:

[TestClass]
public class MyTests
{
   [TestMethod]
   private void AddData_SwitchValueOf15_ShouldAddToStorageTwo()
   {
      // Mock the repository then add it to the service
      Mock<IRepository> mockRepository = new Mock<IRepository>();

      MyService service = new MyService
      {
         Repository = mockRepository 
      };

      MyDataObject myDataObject = new MyDataObject();
      // Assign some data to myDataObject

      // This should insert myDataObject into StorageTwo
      service.AddData(myDataObject, 15);

      // Check that the correct method was called once, with our parameter
      mockRepository.Verify(r => r.AddToStorageTwo(myDataObject), Times.Once());

      // Check that the other methods were never called, with any input
      mockRepository.Verify(r => r.AddToStorageOne(It.IsAny<MyDataObject>()), Times.Never());
      mockRepository.Verify(r => r.AddToStorageThree(It.IsAny<MyDataObject>()), Times.Never());
   }
}