2

随着我对单元测试的了解越来越多,我开始意识到该领域众所周知的行为(交互)与状态验证方法。

在执行某个操作后验证某个系统的状态对我来说似乎是合乎逻辑的。

关于验证被测类与其他组件的交互是否可以这样说?我仍然不是 100% 相信的。

例如:

public void DoSomething(IDependency dependency)
{
    // some code ...

    dependency.Method();

    dependency.Method2();

    // some more code ...
}

DoSomething() 的当前实现调用 Method() 和 Method2() 并且可以使用模拟测试这一事实是否具有任何实际价值?

这两种方法的调用不是 DoSomething() 的实现细节吗?

与基于状态的验证相比,验证交互似乎要脆弱得多,并且还会破坏封装(测试这种方法隐藏的东西)。

4

2 回答 2

3

如果一个规范(有人称之为测试)要求进行某种交互,您还应该验证是否是这种情况并为此进行单元测试。例如,如果需要 SUT 保存文件,您可能应该验证该文件是否IFileSystem.Save(...)已被调用。如果需要 SUT 使用新文件名保护它(如果文件存在),您应该验证是否IFileSystem.Save(...)已使用正确的文件名调用并且IFileSystem.Exists(...)已被调用。这是最好的交互测试。

使用FakeItEasy它看起来像这样:

// arrange
var fileSystem = A.Fake<IFileSystem>();
A.CallTo(() => fileSystem.Exists("file.txt")).Returns(true);
A.CallTo(() => fileSystem.Exists("file1.txt")).Returns(false);
var sut = new SystemUnderTest(fileSystem);

// act
sut.DoSomething(); // do something that eventually saves file.txt

// assert
A.CallTo(() => fileSystem.Exists("file.txt")).MustHaveHappened();
A.CallTo(() => fileSystem.Exists("file1.txt")).MustHaveHappened();
A.CallTo(() => fileSystem.Save("file1.txt")).MustHaveHappened();
于 2013-03-13T21:21:39.633 回答
0

嗯,好吧,如果你想验证我的行为,DoSomething(IDependency dependency)我会说你肯定想验证你的依赖项是否被调用。

这就是模拟通常的用途。你想确保你的依赖在你的SuT. 您不想被依赖项的实现细节所困扰。

所以我很好的测试会是这样的:

[Test]
public void DoSomething()
{
    var sut = new Whatever();
    var dependencyMock = MockRepository.GenerateMock<IDependency>();
    dependencyMock.Stub(() => mock.Method1()).Repeat = 1;
    dependencyMock.Stub(() => mock.Method2()).Repeat = 1;
    sut.DoSomething(dependencyMock);

    // verify that expected methods are being called
    dependencyMock.VerifyAllExpectations(); 

    // make some meaningful assert for sut.
    Assert. // ... etc
}

请注意,我在没有打开工作室的情况下输入了这个,所以所有模错字模错误:)。只是给你一个想法。


如果您只是将功能“粘合”在一起。就像一个类在依赖对象上调用方法之后什么都不做一样,您可能值得研究是否应该重构“代码气味”。但是在你上面提供的例子中,我会说你没问题,你应该去做。

于 2013-03-13T21:21:29.463 回答