如何单元测试,如果调用静态记录发生
问题描述:
考虑用try catch
这样的方法:如何单元测试,如果调用静态记录发生
try
{
person = this.personRepo.GetPerson(name);
}
catch (PersonException)
{
LogHelper.LogDebug("PersonService", "No Person found!");
}
在单元测试中,personRepo
是伪造与FakeItEasy:
A.CallTo(() => this.personRepository.GetPerson(personName)).Throws(new PersonException("Person not found"));
问题:
如何检查静态记录器是否被调用?
答
这里的假设是personRepo
被注入到被测主题中。因此我也假设你正在使用DI。
当前显示的代码与静态实现问题紧密耦合,这使得难以单独测试主题。
为了使主题更加灵活,更易于维护和隔离测试,主题需要重构以取决于抽象而不是结核。
在抽象背后封装静态LogHelper
。
public interface ILogger {
void LogDebug(string category, string msg);
//...other members
}
这将包装所需的行为/功能
public class LogHelperWrapper : ILogger {
public void LogDebug(string source, string msg) {
LogHelper.LogDebug(source, msg);
}
//...other members
}
主题会利用抽象,这将重构通过构造注射遵循显式依赖的原则。
private ILogger log; //set via constructor injection
try {
person = this.personRepo.GetPerson(name);
} catch (PersonException) {
this.log.LogDebug("PersonService", "No Person found!");
}
这将允许被测试者在隔离测试时接收替换物。
//Arrange
var logger = A.Fake<ILogger>();
//...other arrangements
//Act
//...exercise test
//Assertion
A.CallTo(() => logger.LogDebug("PersonService", "No Person found!"))
.MustHaveHappened(Repeated.Exactly.Once);
//...other assertions.
因为'LogHelper.LogDebug'是静态方法 - 你不能嘲笑它。所以你需要测试'LogDebug'的实际行为。如果它写入文件 - 读取文件,如果写入数据库 - 读取数据库。如果'LogHelper'可配置 - 您可以将其配置为可以轻松测试的输出(例如MemoryStream)。但是洁具,它是静态方法,如果你并行运行测试 - 其他测试会受到相同配置的影响。适当的可测试解决方案 - 引入“记录器”的抽象并将其注入课堂。实际的实现仍然可以调用静态方法。 – Fabio
这通常很复杂。这也是避免静力学的一个原因。您可以使用MS Fakes(Shim Types),但AFAIK您需要Visual Studio Enterprise(或以前的最终版本)。否则,您可能会应用重构。如果依赖注入不是您的选择,那么您可以首先引入一个单例LogHelper.Instance.LogDebug(...),它可以在单元测试中设置。 – Peit
如果发生异常,您可以尝试测试。但在测试结束时,您应该删除已保存的数据。不知道这是否是最好的方法。 – Sasha