2010-09-29 60 views
5

假设我有一个执行某种计算的私人例行:如何在不重构的情况下对私有代码进行单元测试来分离类?

private function TCar.Speed: float 
{ 
    Result = m_furlogs * 23; 
} 

但现在我要开始更彻底地测试这个计算,所以我重构它到一个单独的函数:

public function TCar.Speed: float 
{ 
    Result = CalculateSpeed(m_furlogs); 
} 

private function TCar.CalculateSpeed(single furlogs): float 
{ 
    Result = furlogs * 23; 
} 

现在我可以CalculateSpeed进行各种测试:

Check(CalculateSpeed(0) = 0); 
Check(CalculateSpeed(1) = 23); 
Check(CalculateSpeed(2) = 46); 
Check(CalculateSpeed(88) = -1); 

除了我不能执行这些测试,因为CalculateSpeedTCar是私有的。抽象的单元测试tennant是你永远不会测试私有代码 - 只有公共接口。作为一个实际问题,* x * Unit通常不能访问正在测试的独立类的私有方法。

问题是,没有其余的类被设置为处理单元测试。这是第一个有任何测试的例程。而且配置主机类是一套初始条件非常困难,这将允许我用每一组我想要的输入来测试调用CalculateSpeed

唯一的选择,我可以看到,被搬进搬出这个私人计算到它自己的TCarCalculateSpeed类:

public class TCarCalculateSpeed 
{ 
    public function CalculateSpeed(float furlogs) 
    { 
     Result = furlogs * 23; 
    } 
} 

全班,致力于揭露一个方法,那应该是私人的,只是这样我就可以测试它?

类爆炸。

加上它是私人的。如果我想让它公开,我宁愿将它推广到公开知名度 - 至少这样我保存一个单独的课程正在创建。

我想添加一些单元测试;但随着代码的变化,它只能以小块完成。我不能完全重新设计运行12年的软件,可能会破坏一切,因为我想测试一个内部计算。

我现在的,最好的,思维是一个Test方法添加到我的Car类,只是调用:

TCar Car = new TCar(); 
Car.RunTests; 

public procedure TCar.RunTests 
{ 
    Check(CalculateSpeed(0) = 0); 
    Check(CalculateSpeed(1) = 23); 
    Check(CalculateSpeed(2) = 46); 
    Check(CalculateSpeed(88) = -1); 
} 

但现在我必须弄清楚如何有TCar.RunTests得到由外部TestRunner触发,它只被设计为使用TestCase类。

注:我已经尝试过我最深入的混合一堆语言的语法。换句话说:语言是不可知的。

+0

我不知道如何以语言不可知的方式来完成它,但在VS/.NET中,它将创建一个Accessor类,它会影响您的真实课程并将所有内容公开化,以便您可以对其进行测试。 – CaffGeek 2010-09-29 21:36:28

+0

这可能是我可以得到的答案。我必须使方法'protected',而不是'private',但然后我可以从我的单元测试代码文件访问受保护的成员。 – 2010-10-01 21:04:25

回答

3

这实际上并不完全是语言不可知的,因为绕过它们的保护机制和策略在语言方面差异很大。

但是大多数语言都以某种形式提供绕过,而且正如其他人所指出的那样,在私人和公众之间有时会进行保护,这使得测试更容易。

例如,在Java中,如果真的需要反射可以用于私有内容,并且可以对事物进行保护或封装为私有,以便您不需要反射。

一般来说,如果某件事足够复杂以至于需要测试,它不应该作为私有方法或类被埋在别的东西中。它正在做一些保证自己班级的事情。

与其担心类的数量,不如担心它们的大小和复杂性。许多坚持Single Responsibility Principle的小班比内部处理复杂事物的少数班级要好。

+0

几乎所有人都提倡使用某种语言技巧来绕过对此方法的可访问性保护。这可能是我最终使用的语言,我正在使用。尽管你们大多数人都有相同的想法,但我选择了给予杜罗比的答案。 – 2010-10-01 21:07:54

+1

@Ian - 谢谢。但请记住,我的主要建议和其他几个建议的主要建议是,您实际上已将其提交到另一个班级,并通过更正常的方式进行测试。很高兴知道如何绕过保护措施,但通常不是必须的。 – 2010-10-01 23:13:52

1

您可以用不同的m_furlogs初始值创建TCar类的多个实例吗?你在任何地方都有速度吸气吗?如果是这样的话,你可以进行验证。

如果它只在内部使用,并且您真的想测试它,您可以创建一个公用类,该类包含简单计算的逻辑。我知道这是重构,但这不是你可能想象的类爆炸。

+0

第二段+1。拆分它是一种折衷,我认为在每种情况下都需要仔细考虑。主要共识是使用语言的技巧绕过对象保护并在原地进行测试。幸运的是,我的语言有这样的黑客 - 所以我会这样做。 – 2010-10-01 21:10:28

3

如果一种方法很复杂(而且风险)足以自行测试,那么值得为它创建一个类或使其成为现有类的公共成员 - 无论哪种方法更合适,值得考虑现有类的特性。

1

也许你可以创建一个测试类,它可以从你的测试类派生出来吗?

这里是另一个SO question

+0

我使用的框架不能这样做,但它是一个有效的想法。 +1 – 2010-10-01 21:06:40

1

在某些语言中的例子,有私人和公众之间的中间地带。您可以将一个逻辑上私有的方法暴露给单元测试,而不会将其暴露给全世界。

在方法文档中,您可以记录该方法是专用的,但可用于单元测试。例如,在Java中,可以使用私有方法package protected,并将单元测试放在同一个包中。在C#中,如果我记得正确的话,你可以把它放在内部。在C++中,单元测试可能是朋友。

1

如果您的语言支持编译器定义,那么您可以使用这些优点。

(在Delphi实施例的代码)

在您的单元测试项目,设定一个编译器条件限定,无论是使用项目的选项或在您在每一个单元在该项目包括一个包含文件。

{$DEFINE UNIT_TESTS} 

在你的类代码,请有条件的定义和相应的公共或protected和private之间切换:,而在

{$IFDEF UNIT_TESTS} 
    public // or protected 
{$ELSE} 
    private 
{$ENDIF} 
    function CalculateSpeed: float; 

这意味着你的单元测试将有他们需要你的方法访问生产代码它仍然是私人的。

+0

这是个好消息。 – 2010-10-01 21:06:03

相关问题