2010-01-20 75 views
13

我试图进入单元测试为它引入的明显积极,我试图编写一个单元测试我为前一天写的类。 (我知道这与TDD相反,请耐心等待)PHPUnit测试问题 - 如何单元测试我的课

我的课程Image与其他一些用于图像处理。

Image本质上包装GD图像资源并将数据与其一起存储。例如,Image一个实例将始终包含它的当前状态,即其新的宽度/高度,如果调整,将原始图像数据等

Image类也包含了方法,

  • 创建本身来自文件,字符串数据或URL,例如$image->loadFromPath()
  • 从当前的Image实例的属性创建新的GD图像资源,例如,图像大小调整,以保持背景透明度等
  • 克隆使用的GD图像资源的操作类

我挣扎什么是单位如何测试这个类正确以及PHPUnit。我已经完成了一些阅读,并且我对如何解决这个问题有一些矛盾的想法,我不知道什么是正确的。

  1. 为类的每种方法写一个测试。我在某处读到我应该测试每种方法。然而,一些方法运行其他方法(我可以添加),所以你有一个依赖链。但我也读过每个单元测试应该独立于另一个。那么如果是这样的话我该怎么办?
  2. 将每个测试写为类的使用路线。我还在某处读到,每个测试应该代表1个路径/使用路线,您可以在课程中使用。因此,如果您覆盖每一种用法,您最终将获得完整的代码覆盖率。

那么,哪些是正确的,如果有的话?

+0

你知道代码覆盖率吗?国际海事组织(IMO)至少运行一行代码至关重要,而不是为每一种方法都创建一个测试,这对于你提到的原因并不总是必要的。 – Franz 2010-01-20 15:54:32

+0

+1进入UnitTests – Gordon 2010-01-20 15:59:22

+0

我知道什么代码覆盖率是肯定的,你应该瞄准100%,这就是说每一行至少应该运行一次。 因此,最好是编写测试用例,其中每个测试都是您的类执行的操作,而不是针对特定方法的每个测试? – 2010-01-20 16:00:33

回答

8

应该编写单元测试来评估一个类的公共接口。您的测试用例应该使用该类,因为您打算在您的程序中使用它。这里的想法是测试该类的行为(预期的,意外的或边缘条件)。

你发布的这两个想法都是正确的。从理论上讲,你应该有足够的测试用例(通过你的代码的路由)运行你的类中的所有方法。如上所述,100%的测试覆盖率是一个不错的目标,但并不总是现实的。

另外,在GD的情况下,要小心编写测试GD功能的单元测试(它已经过测试,不需要再浪费时间再次测试)。我会read up on在PHPUnit手册中使用PHPUnit的模拟和存根(并嘲笑文件系统)。

下面是一个例子测试可能是什么样子:

public function testImageIsResized() 
{ 
    $image = new Image(); 
    $image->loadFromPath('some/path'); 
    $image->resize(200, 300); 
    $this->assertEquals(200, $image->getWidth()); 
    $this->assertEquals(300, $image->getHeight()); 
} 

现在,根据图像类的预期行为,这个测试可能通过没有问题,或者因为它期待新的尺寸可能会失败以成比例地限制到原始图像尺寸。但是我们没有明确地调用在测试本身中检查该约束的内部方法。

+0

非常感谢我的想法!感谢您的总结 – 2010-01-20 19:25:29

5

您可以使用covers annotation来指定测试是否涵盖多种方法。因此,如果您的某个方法调用另一种方法,则可以将该注释添加到测试的docblock中,并将其添加到代码覆盖率统计信息中,例如,

/** 
* @test 
* @covers MyClass::something() 
* @covers MyClass::_somethingElse() 
*/ 
public function somethingWorksAsExpected() 
{ 
    $this->assertSame($expected, $this->testObject->something()); 
} 

对于个人项目,100%的代码覆盖率的罚款。不过,我曾在会议上看过100%被怀疑是必要的会议。尽管有所有好处,但测试需要花时间编写,并且在预算项目中,仅仅测试80/20就足够了,并且可以忽略应用程序的不重要的低优先级功能。

至于如何测试你的班级,看看Behaviour Driven Development in the PHPUnit Manual的章节。就你而言,我会测试你在问题中描述的功能。

0

斯蒂芬·梅尔罗斯说:

然而,一些方法运行 别人(这是正确的我想补充),所以你 然后有依赖关系链。但我也 读取每个单元测试应该 独立于其他

测试独立性不是不测试相同的代码两次,它是关于一个测试的结果(或缺乏导致的)是否影响另一个的结果。如果您的第一个测试插入一些数据,然后在删除数据之前失败,则您的第二个测试可能会得到与预期不同的结果。理想情况下,您应该能够以随机顺序运行测试,或者运行一些测试而不是其他测试。