我希望对测试一个类的不同选项有一些见解,该类有责任在给定两个其他对象的情况下创建一个Sample
对象。
我的对象的API如下:
public interface ISampleCreator
{
Sample CreateSample(Order order, SampleService sampleService);
}
此方法中的逻辑可分为三个部分:
初始化Sample
的一些简单属性(取决于Order
和SampleService
)。
为Sample
设置一个新的唯一名称(取决于Order.Samples
和SampleService
)。
为Sample
设置一些其他字段(取决于SampleService
)。
我的问题是,如果我想彻底测试这个方法,我会在很多不同的情况下考虑一些复杂的设置。
我的第一个想法是提取一个类来为第2点生成唯一的名称,并提取一个类来为该样本生成其他字段。
然后我可以独立测试这两个类,我可以模拟它们以减少对CreateSample
方法的测试。例如:
[TestMethod]
public void CreateSampleTest()
{
Order order = new Order();
SampleService sampleService = new SampleService();
Mock<ISampleNameGenerator> mockNameGenerator = new Mock<ISampleNameGenerator>();
mockNameGenerator.Setup(x => x.GenerateSampleName(order.Samples, sampleService))
.Returns("Generated name");
Mock<ISampleFieldsCreator> mockFieldsCreator = new Mock<ISampleFieldsCreator>();
List<SampleField> sampleFields = new List<SampleField>();
mockFieldsCreator.Setup(x => x.CreateFieldsForNewSample(sampleService))
.Returns(sampleFields);
SampleCreator sampleCreator = new SampleCreator(mockNameGenerator.Object, mockFieldsCreator.Object);
Sample sample = sampleCreator.CreateSample(order, sampleService);
Assert.AreEqual("Generated name", sample.Name);
Assert.AreEqual(sampleFields, sample.Fields);
Assert.AreEqual(order, sample.Order);
Assert.AreEqual(sampleService, sample.SampleService);
}
我对这种方法的问题是,我正在模拟我拥有的类,并且不访问任何外部资源:基本上,我正在进行基于模拟的测试,以简化测试的设置。
您如何看待这种方法?
您能否提出其他替代方案以及为何会这样做?
答案 0 :(得分:2)
我使用这种方法的问题是,我正在模拟我拥有的类,并且不能访问任何外部资源:基本上,我正在进行基于模拟的测试,作为简化测试设置的一种方法。
假设您应该只模拟加入外部资源的东西是错误的。你模拟依赖,无论它们是什么。模拟的目的是将实际的类/方法逻辑与其他组件的操作细节隔离开来(依赖)。
看看你介绍的重构 - 提取唯一名称生成到单独的类。这听起来很合理,因为该过程可能涉及全新的限制和内部知识,而您的原始对象构建方法并不需要拥有。
解耦代码通常是个好主意,因为它会导致更多单任务导向的类,更容易的测试,更容易的对象组合,更多的代码重用。单元测试通常有助于以您发现的方式完全发现这些改进区域 - 使测试变得困难/过于复杂而无法首先编写。
长话短说 - 你的方法是正确的。
答案 1 :(得分:1)
单元测试始终是一种平衡行为。显然,您希望测试CreateSample()按预期工作。当它与Order和SampleService交互时,理想情况下,您的测试将在测试中使用这些对象的实例。但是,正如您所指出的那样,这会使测试的设置变得复杂,这会产生额外的工作并阻碍彻底的测试。
关于如何构建代码的一点要注意的是Order和SampleService是具体的类;您已将CreateSample()与这些类相结合。如果你有CreateSample()使用IOrder和ISampleService,你将把方法与其他类分离,因此测试的设置可能会更容易。
嘲弄你的物品是妥协。它可以简化测试,但是,您必须意识到您的测试不是测试您的系统,而是部分模拟您的系统。有时,这可以帮助。它也可能导致虚假的安全感。您可以最终测试所有部件,但只有当您将这些部件连接在一起时,整个部件才会崩溃。