对不返回任何内容的方法进行单元测试的最佳方法是什么?特别是在C#中。
我真正想测试的是一种采用日志文件并将其解析为特定字符串的方法。然后将字符串插入数据库中。之前没有做过什么,但是对于TDD来说是非常新的,我想知道是否有可能对此进行测试,或者它是否真的没有经过测试。
对不返回任何内容的方法进行单元测试的最佳方法是什么?特别是在C#中。
我真正想测试的是一种采用日志文件并将其解析为特定字符串的方法。然后将字符串插入数据库中。之前没有做过什么,但是对于TDD来说是非常新的,我想知道是否有可能对此进行测试,或者它是否真的没有经过测试。
Answers:
如果某个方法不返回任何内容,则为以下之一
命令式方法-您可以验证任务是否实际执行。验证状态更改是否确实发生。例如
void DeductFromBalance( dAmount )
可以通过验证此消息后的余额是否确实小于初始值dAmount来进行测试
信息方法-作为对象公共接口的成员很少,因此通常不进行单元测试。但是,如果必须,您可以验证是否对通知进行了处理。例如
void OnAccountDebit( dAmount ) // emails account holder with info
可以通过验证是否已发送电子邮件进行测试
发布有关您的实际方法的更多详细信息,人们将能够更好地回答。
更新:您的方法正在做两件事。实际上,我将其分为两种可以独立测试的方法。
string[] ExamineLogFileForX( string sFileName );
void InsertStringsIntoDatabase( string[] );
通过为第一种方法提供虚拟文件和期望的字符串,可以轻松地验证String []。第二个有点棘手..您可以使用Mock(在模拟框架上使用Google模仿或搜索stackoverflow)来模仿数据库,也可以命中实际的数据库并验证字符串是否插入正确的位置。检查此主题以获取一些好书...如果您处于紧要关头,我建议进行实用单元测试。
在代码中,它将像
InsertStringsIntoDatabase( ExamineLogFileForX( "c:\OMG.log" ) );
无效的返回类型/子例程是旧消息。大约8年以来,我还没有做过Void返回类型(除非我非常懒惰)(从回答这个问题开始,所以在问这个问题之前不久)。
而不是像这样的方法:
public void SendEmailToCustomer()
创建一个遵循Microsoft的int.TryParse()范例的方法:
public bool TrySendEmailToCustomer()
从长远来看,也许您的方法不需要返回任何信息以供使用,但是对调用者来说,在执行其工作之后返回方法的状态非常有用。
同样,布尔不是唯一的状态类型。在很多情况下,先前制作的子例程实际上可以返回三个或更多不同的状态(良好,正常,不良等)。在这种情况下,您只需要使用
public StateEnum TrySendEmailToCustomer()
但是,尽管Try-Paradigm在某种程度上回答了有关如何测试无效收益的问题,但还有其他考虑因素。例如,在“ TDD”周期中/之后,您将在“重构”,并且注意到您正在用自己的方法做两件事……从而破坏了“单一责任原则”。因此,首先应注意这一点。其次,您可能已经了解了一个依赖性...您正在处理“持久性”数据。
如果要在问题方法中进行数据访问,则需要重构为n层或n层架构。但是我们可以假设,当您说“然后将字符串插入数据库”时,实际上意味着您正在调用业务逻辑层或诸如此类。是的,我们假设。
实例化对象后,您现在了解到对象具有依赖性。这是您需要决定是否要对对象或方法进行依赖注入的时候。这意味着您的构造方法或问题方法需要一个新的参数:
public <Constructor/MethodName> (IBusinessDataEtc otherLayerOrTierObject, string[] stuffToInsert)
现在,您可以接受业务/数据层对象的接口,可以在单元测试期间将其模拟出来,而不必依赖或担心“意外”集成测试。
因此,在您的实时代码中,您传入一个REAL IBusinessDataEtc
对象。但是在单元测试中,您传入了MOCK IBusinessDataEtc
对象。在该Mock中,您可以包含非接口属性,例如,int XMethodWasCalledCount
或诸如此类,其状态在调用接口方法时会更新。
因此,单元测试将遍历您的问题方法,执行其具有的任何逻辑,并在您的IBusinessDataEtc
对象中调用一个或两个或一组选定的方法。在单元测试结束时执行断言时,现在有几项要测试。
IBusinessDataEtc
对象的状态。有关构造级别上的依赖项注入思想的更多信息……与单元测试有关……请查看Builder设计模式。它为您拥有的每个当前接口/类增加了一个接口和类,但是它们非常小,并且增加了巨大的功能以实现更好的单元测试。
public void sendEmailToCustomer() throws UndeliveredMailException
吗?
void
方法中,尤其是在面向对象的语言中,它一直是唯一的选择。微软最古老的替代方案是我所讨论的Try-Paradigm,以及诸如Monads / Maybes之类的功能样式范例。因此,Commands(在CQS中)仍然可以返回有价值的状态信息,而不必依赖于引发(这类似于GOTO
(我们知道是不好的))。投掷(和goto)速度慢,难以调试,也不是好习惯。
试试这个:
[TestMethod]
public void TestSomething()
{
try
{
YourMethodCall();
Assert.IsTrue(true);
}
catch {
Assert.IsTrue(false);
}
}
ExpectedAttribute
设计使这个测试更清晰。
使用Rhino Mocks设置可能发生的呼叫,操作和异常情况。假设您可以模拟或存根方法的某些部分。如果不了解有关方法甚至上下文的某些细节,很难知道。
无论您使用哪种实例来调用void方法,都可以使用,Verfiy
例如:
就我而言,它_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);
}
是Verify
抛出一个异常,由于测试将失败的方法的失败?