对一个不返回任何东西的方法进行单元测试的最佳方法是什么?特别是在c#中。

我真正想测试的是一个方法,它接受一个日志文件并解析它的特定字符串。然后将字符串插入到数据库中。没有什么是以前没有做过的,但对于TDD来说是非常新的,我想知道是否有可能测试这个,或者它是没有真正测试过的东西。


当前回答

无论你使用什么实例来调用void方法,你可以使用,验证

例如:

在我的例子中,它的_Log是实例,LogMessage是要测试的方法:

try
{
    this._log.Verify(x => x.LogMessage(Logger.WillisLogLevel.Info, Logger.WillisLogger.Usage, "Created the Student with name as"), "Failure");
}
Catch 
{
    Assert.IsFalse(ex is Moq.MockException);
}

验证是否由于测试将失败的方法失败而抛出异常?

其他回答

测试它的副作用。这包括:

它会抛出任何异常吗?(如果应该的话,检查一下。如果不应该,尝试一些角落的情况,如果你不小心,可能会- null参数是最明显的事情。) 它能很好地处理参数吗?(如果它们是可变的,它是否会在不应该的时候改变它们,反之亦然?) 它是否对正在调用它的对象/类型的状态有正确的影响?

当然,您可以测试的内容是有限的。例如,您通常不能对每个可能的输入进行测试。实用的测试——足够让你相信你的代码设计得当,实现正确,并且足够作为调用者可能期望的补充文档。

Void返回类型/子例程已经过时了。我没有做一个Void返回类型(除非我是非常懒惰)在像8年(从这个答案的时间,所以只是在这个问题被问之前的一点)。

而不是像这样的方法:

public void SendEmailToCustomer()

创建一个遵循微软int.TryParse()范例的方法:

public bool TrySendEmailToCustomer()

也许您的方法在长期使用中不需要返回任何信息,但是在它执行其工作后返回方法的状态对调用者来说是一个巨大的用处。

而且,bool并不是唯一的状态类型。有很多次,以前制作的子例程实际上可以返回三种或更多不同的状态(好,正常,坏,等等)。在这种情况下,你只需使用

public StateEnum TrySendEmailToCustomer()

然而,尽管Try-Paradigm在某种程度上回答了如何测试void返回的问题,但也有其他考虑因素。例如,在“TDD”周期中/之后,你会“重构”,并注意到你用你的方法做了两件事……从而打破了“单一责任原则”。所以首先要解决这个问题。其次,您可能已经确定了一个依赖项……您正在接触“持久”数据。

如果您正在使用所讨论的方法进行数据访问,则需要将其重构为n层或n层体系结构。但我们可以假设,当您说“字符串随后被插入到数据库中”时,您实际上是在调用业务逻辑层或其他东西。是的,我们假设是这样。

当对象实例化后,您现在就知道对象具有依赖关系了。这时你需要决定是在对象上还是在方法上进行依赖注入。这意味着你的构造函数或方法需要一个新的参数:

public <Constructor/MethodName> (IBusinessDataEtc otherLayerOrTierObject, string[] stuffToInsert)

现在您可以接受业务/数据层对象的接口,您可以在单元测试期间模拟它,无需依赖或担心“意外”集成测试。

因此,在您的活动代码中,您传递一个REAL IBusinessDataEtc对象。但是在单元测试中,您传递了一个MOCK IBusinessDataEtc对象。在这个Mock中,你可以包括非接口属性,比如int XMethodWasCalledCount,或者在调用接口方法时更新状态的属性。

因此,您的单元测试将遍历您的Method(s)-In-Question,执行它们所具有的任何逻辑,并调用IBusinessDataEtc对象中的一个或两个或一组选定的方法。当你在单元测试的末尾执行断言时,你现在有两个东西要测试。

“子例程”的状态,现在是一个尝试范式方法。 模拟IBusinessDataEtc对象的状态。

有关构造层依赖注入思想的更多信息…因为它们与单元测试有关……查看Builder设计模式。它为当前的每个接口/类增加了一个接口和类,但它们非常小,为更好的单元测试提供了巨大的功能增加。

使用Rhino mock来设置可能预期的调用、操作和异常。假设您可以模拟或去掉方法的某些部分。如果不了解关于方法甚至上下文的一些细节,就很难知道。

它会对一个对象产生一些影响....查询效果的结果。如果没有明显的效果,就不值得进行单元测试!

这取决于它在做什么。如果它有参数,则传入模拟,以便稍后询问是否使用正确的参数集调用了它们。