对不返回任何内容的方法进行单元测试的最佳方法是什么?特别是在c#。
我真正想要测试的是一种获取日志文件并针对特定字符串进行解析的方法。然后将字符串插入数据库。没有什么比以前没有做过但对TDD来说是非常新的我想知道是否有可能测试这个或者它是否真的没有经过测试。
答案 0 :(得分:135)
如果方法没有返回任何内容,则可以是以下任何一种
命令式方法 - 您可以验证任务是否实际执行。验证是否实际发生了状态更改。 e.g。
void DeductFromBalance( dAmount )
可以通过验证此消息的余额是否确实小于dAmount的初始值来测试
信息方法 - 很少作为对象的公共接口的成员...因此通常不进行单元测试。但是,如果必须,您可以验证是否要对通知进行处理。 e.g。
void OnAccountDebit( dAmount ) // emails account holder with info
可以通过验证电子邮件是否正在发送进行测试
发布有关您的实际方法的更多详细信息,人们将能够更好地回答。
更新:您的方法正在做两件事。我实际上将它分成两种方法,现在可以独立测试。
string[] ExamineLogFileForX( string sFileName );
void InsertStringsIntoDatabase( string[] );
通过为第一个方法提供虚拟文件和预期的字符串,可以轻松验证String []。第二个有点棘手..你可以使用Mock(google或在模拟框架上搜索stackoverflow)来模仿数据库或点击实际数据库并验证字符串是否插入到正确的位置。检查this thread是否有一些好书...如果你处于紧张状态,我会建议实用单位测试。
在代码中,它将像
InsertStringsIntoDatabase( ExamineLogFileForX( "c:\OMG.log" ) );
答案 1 :(得分:55)
测试其副作用。这包括:
当然,你可以测试的很多是有限的。例如,您通常无法测试每个可能的输入。实用性测试 - 足以让您确信您的代码设计得恰当并且正确实现,并且足以充当调用者可能期望的补充文档。
答案 2 :(得分:27)
一如既往:测试该方法应该做什么!
它应该在某处改变全局状态(uuh,代码味道!)吗?
它应该调用接口吗?
使用错误的参数调用时是否会抛出异常?
使用正确的参数调用时是否应该抛出异常?
它应该......?
答案 3 :(得分:9)
Void返回类型/子例程是旧消息。在8年的时间里,我还没有做出Void返回类型(除非我非常懒惰)(从这个答案的时候起,所以在问这个问题之前就已经有点了。)
而不是类似的方法:
public void SendEmailToCustomer()
制作一个遵循微软的int.TryParse()范例的方法:
public bool TrySendEmailToCustomer()
也许没有任何信息需要您的方法返回以供长期使用,但在执行其工作后返回方法的状态对调用者来说是一个巨大的用途。
另外,bool不是唯一的州类型。有许多次,以前制作的子程序实际上可以返回三种或更多种不同的状态(Good,Normal,Bad等)。在这些情况下,您只需使用
public StateEnum TrySendEmailToCustomer()
然而,虽然Try-Paradigm在某种程度上回答了关于如何测试void返回的问题,但还有其他考虑因素。例如,在" TDD"期间/之后循环,你会"重构"并注意到你正在用你的方法做两件事......从而违反了单一责任原则。"所以应该先照顾好。其次,你可能已经认识到一种依赖...你正在触摸"持续"数据
如果您正在使用相关方法中的数据访问内容,则需要重构为n层或n层体系结构。但我们可以假设,当你说"然后将字符串插入到数据库中时,你实际上意味着你正在调用业务逻辑层或其他东西。雅,我们假设。
当您的对象被实例化时,您现在知道您的对象具有依赖性。这是当您需要决定是否要对对象或方法执行依赖注入时。这意味着您的构造函数或有问题的方法需要一个新参数:
public <Constructor/MethodName> (IBusinessDataEtc otherLayerOrTierObject, string[] stuffToInsert)
现在您可以接受业务/数据层对象的接口,您可以在单元测试期间将其模拟出来,并且没有依赖性或担心&#34;意外&#34;集成测试。
因此,在您的实时代码中,您传入一个REAL IBusinessDataEtc
对象。但是在单元测试中,您传入一个MOCK IBusinessDataEtc
对象。在那个Mock中,你可以包括非接口属性,如int XMethodWasCalledCount
或者在调用接口方法时更新状态的东西。
因此,您的单元测试将通过您的方法-In-Question,执行他们拥有的任何逻辑,并在IBusinessDataEtc
对象中调用一个或两个或一组选定的方法。当您在单元测试结束时进行断言时,您现在需要测试几件事。
IBusinessDataEtc
对象的状态。有关构建级别的依赖注入思想的更多信息......因为它们与单元测试有关...请查看构思器设计模式。它为您拥有的每个当前接口/类增加了一个接口和类,但它们非常小,并且为更好的单元测试提供了巨大的功能增加。
答案 4 :(得分:5)
它会对对象产生一些影响....查询效果的结果。如果它没有明显效果,那就不值得单元测试了!
答案 5 :(得分:4)
大概这个方法做了什么,而不仅仅是回归?
假设是这种情况,那么:
如果你让我们知道方法的作用,我可以更具体一点。
答案 6 :(得分:4)
试试这个:
[TestMethod]
public void TestSomething()
{
try
{
YourMethodCall();
Assert.IsTrue(true);
}
catch {
Assert.IsTrue(false);
}
}
答案 7 :(得分:3)
使用Rhino Mocks设置可能需要的呼叫,操作和例外。假设您可以模拟或删除方法的一部分。很难知道这里有关于方法甚至上下文的一些具体细节。
答案 8 :(得分:2)
取决于它在做什么。如果它有参数,那么传入你稍后可能会询问的模拟是否已使用正确的参数集调用它们。
答案 9 :(得分:0)
您使用什么实例来调用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
是否会引发异常,测试会失败吗?
答案 10 :(得分:0)
您甚至可以这样尝试:
[TestMethod]
public void ReadFiles()
{
try
{
Read();
return; // indicates success
}
catch (Exception ex)
{
Assert.Fail(ex.Message);
}
}