模拟两个依赖项
最好的解决方案是模拟出你的两个依赖项。理想情况下,您的具体类应该在构造时注入这些依赖项。
您只需要在 Process 中测试 3 件事。
- 根据模拟输入正确输出 Process
- 行为 =>(是否按预期调用了 dependency1.GetSomeList 等)
- 沿所有逻辑路径正确输出 Process
你永远不应该使用具体的依赖,这会导致你有脆弱的单元测试,因为你将依赖于你无法控制的数据。要正确测试方法,您需要提供无效输入(空值、空字符串、极大数字、负数)等,以试图破坏当前预期的功能。以及自然有效的输入。
您也不需要复制依赖项的实际功能。您唯一需要测试的是代码在所有逻辑路径上的正确功能。如果您需要更改dependency2 的输出以测试第二个代码路径。那是另一个测试。
将您的测试分成大量细粒度的测试用例的好处是,如果您更改 Process 内部的任何内容,并运行您的单元测试。您确切地知道问题出在哪里,因为现在有 3 / 50 个测试失败了,并且您知道在哪里解决您的问题,因为它们都在测试 1 个特定的东西。
使用 Rhino Mocks 会变成这样
private IDependency1 _dependency1;
private IDependency2 _dependency2;
private ClassToBeTested _classToBeTested;
[SetUp]
private override void SetUp()
{
base.SetUp();
_dependency1 = MockRepository.GenerateMock<IDependency1>();
_dependency2 = MockRepository.GenerateMock<IDependency2>();
_classToBeTested = new ClassToBeTested(_dependency1, _dependency2);
}
[Test]
public void TestCorrectFunctionOfProcess()
{
int input = 10000;
IList<int> returnList = new List<int>() {1,2,3,4};
// Arrange
_dependency1.Expect(d1 => d1.GetSomeList(input)).Return(returnList);
_dependency2.Expect(d2 => d2.DoSomeProcessing(0))
.AtLeastOnce().IgnoreArguments().Return(1);
// Act
var outputList = _classToBeTested.Process(input);
// Assert that output is correct for all mocked inputs
Assert.IsNotNull(outputList, "Output list should not be null")
// Assert correct behavior was _dependency1.GetSomeList(input) called?
_dependency1.VerifyAllExpectations();
_dependency2.VerifyAllExpectations();
}
更新
IElementProcessor _elementProcessor;
public List<int> Process(int input)
{
List<int> outputList = new List<int>();
List<int> list = this.dependency1.GetSomeList(input);
foreach(int element in list)
{
// ... Do some procssing to element
_elementProcessor.ProcessElement(element);
//Do some more processing
int processedInt = this.dependency2.DoSomeProcessing(element);
// ... Do some processing to processedInt
_elementProcessor.ProcessInt(processedInt);
outputList.Add(processedInt);
}
return outputList;
}
因此,上面发生的有效情况是,您的两个处理现在都被分解为单独的对象。过程几乎不是完全抽象的(这是完美的)。您现在可以单独测试每个元素,以确保在单独的单元测试中功能正确。
上述测试将成为一个集成测试,您可以在其中测试每个依赖项是否被正确调用。