利用单元测试在每个层上对PHP代码进行检查

2016-01-29 12:56 13 1 收藏

利用单元测试在每个层上对PHP代码进行检查,利用单元测试在每个层上对PHP代码进行检查

【 tulaoshi.com - PHP 】

测试驱动的开发和单元测试是确保代码在经过修改和重大调整之后依然能如我们期望的一样工作的最新方法。在本文中,您将学习到如何在模块、数据库和用户界面(UI)层对自己的 PHP 代码进行单元测试。
现在是凌晨 3 点。我们怎样才能知道自己的代码依然在工作呢?

Web 应用程序是 24x7 不间断运行的,因此我的程序是否还在运行这个问题会在晚上一直困扰我。单元测试已经帮我对自己的代码建立了足够的信心 —— 这样我就可以安稳地睡个好觉了。

单元测试 是一个为代码编写测试用例并自动运行这些测试的框架。测试驱动的开发 是一种单元测试方法,其思想是应该首先编写测试程序,并验证这些测试可以发现错误,然后才开始编写需要通过这些测试的代码。当所有测试都通过时,我们开发的特性也就完成了。这些单元测试的价值是我们可以随时运行它们 —— 在签入代码之前,重大修改之后,或者部署到正在运行的系统之后都可以。

PHP 单元测试

对于 PHP 来说,单元测试框架是 PHPUnit2。可以使用 PEAR 命令行作为一个 PEAR 模块来安装这个系统:% pear install PHPUnit2。

在安装这个框架之后,可以通过创建派生于 PHPUnit2_Framework_TestCase 的测试类来编写单元测试。


模块单元测试

我发现开始单元测试最好的地方是在应用程序的业务逻辑模块中。我使用了一个简单的例子:这是一个对两个数字进行求和的函数。为了开始测试,我们首先编写测试用例,如下所示。


清单 1. TestAdd.php

<?php
require_once 'Add.php';
require_once 'PHPUnit2/Framework/TestCase.php';

class TestAdd extends PHPUnit2_Framework_TestCase
{
  function test1() { $this-assertTrue( add( 1, 2 ) == 3 ); }
  function test2() { $this-assertTrue( add( 1, 1 ) == 2 ); }
}
?
 


这个 TestAdd 类有两个方法,都使用了 test 前缀。每个方法都定义了一个测试,这个测试可以与清单 1 一样简单,也可以十分复杂。在本例中,我们在第一个测试中只是简单地断定 1 加 2 等于 3,在第二个测试中是 1 加 1 等于 2。

PHPUnit2 系统定义了 assertTrue() 方法,它用来测试参数中包含的条件值是否为真。然后,我们又编写了 Add.php 模块,最初让它产生错误的结果。


清单 2. Add.php

<?php
function add( $a, $b ) { return 0; }
?

现在运行单元测试时,这两个测试都会失败。


清单 3. 测试失败

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/php/)

% phpunit TestAdd.php
PHPUnit 2.2.1 by Sebastian Bergmann.

FF

Time: 0.0031270980834961
There were 2 failures:
1) test1(TestAdd)

2) test2(TestAdd)


FAILURES!!!
Tests run: 2, Failures: 2, Errors: 0, Incomplete Tests: 0.
 


现在我知道这两个测试都可以正常工作了。因此,可以修改 add() 函数来真正地做实际的事情了。

<?php
function add( $a, $b ) { return $a+$b; }
?
 

现在这两个测试都可以通过了。

清单 4. 测试通过

% phpunit TestAdd.php
PHPUnit 2.2.1 by Sebastian Bergmann.

..

Time: 0.0023679733276367

OK (2 tests)
%

尽管这个测试驱动开发的例子非常简单,但是我们可以从中体会到它的思想。我们首先创建了测试用例,并且有足够多的代码让这个测试运行起来,不过结果是错误的。然后我们验证测试的确是失败的,接着实现了实际的代码使这个测试能够通过。

我发现在实现代码时我会一直不断地添加代码,直到拥有一个覆盖所有代码路径的完整测试为止。在本文的最后,您会看到有关编写什么测试和如何编写这些测试的一些建议。

数据库测试

在进行模块测试之后,就可以进行数据库访问测试了。数据库访问测试 带来了两个有趣的问题。首先,我们必须在每次测试之前将数据库恢复到某个已知点。其次,要注意这种恢复可能会对现有数据库造成破坏,因此我们必须对非生产数据库进行测试,或者在编写测试用例时注意不能影响现有数据库的内容。

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/php/)

数据库的单元测试是从数据库开始的。为了阐述这个问题,我们需要使用下面的简单模式。

清单 5. Schema.sql

DROP TABLE IF EXISTS authors;
CREATE TABLE authors (
  id MEDIUMINT NOT NULL AUTO_INCREMENT,
  name TEXT NOT NULL,
  PRIMARY KEY ( id )
);
 

清单 5 是一个 authors 表,每条记录都有一个相关的 ID。

接下来,就可以编写测试用例了。

清单 6. TestAuthors.ph

来源:http://www.tulaoshi.com/n/20160129/1488163.html

延伸阅读
标签: ASP
       启用 Foreach       许多用户希望能够使用 foreach 遍历我的列表。为此,我需要在类中实现 Ienumerable,并定义一个单独的用于实现 Ienumerable 的类。第一步,测试:      [Test]   public void TestForeach()   {   ...
标签: Java JAVA基础
在测试用例中通过setUp()、tearDown()创建测试固件,只能使这个测试固件在单个测试用例的不同测试方法中共用,如果有多个测试用例都需要使用相同的测试固件,就需要将测试固件抽取到一个独立的类中。JBuilder提供了3个预定义的测试固件类,它们分别是: ·JDBC测试固件(JDBC Fixture):用于获取数据库连接的测试固件,用...
标签: Java JAVA基础
一个产品只有通过检验才能投放市场,同样的,一个业务类也只有在经验测试后才能保证功能的正确性,以便被其他类或程序调用,否则隐藏其中的Bug就蔓延开了。业务功能点测试是测试人员的职责,但业务类API的正确性必须由开发人员保证。 回忆一下最近你所开发的系统,往往一个最难忘的情节是通宵达旦地毯式搜索某个刁专的Bug...
标签: Java JAVA基础
简单的框架 JUnit是由Erich Gamma和Kent Beck开发的开源测试框架,JBuilder集成了这个框架并对此做了扩展。JUnit之所以流行并为广大的开发人员所推崇,一是因为它实战性强,功能强大,二是因为它实在简单。一个产品或框架要能有生命力,最好都具备这样的特点。 简单地讲这个框架提供了许多断言(assert)方法,允...
标签: Java JAVA基础
为了便于讲解,拟通过两个简单的业务类引出测试用例,一个是分段函数类,另一个是字符串处理类,在这节里我们先来熟悉这两个业务类。 分段函数类 分段函数Subsection类有两个函数,sign()是一个符号函数,而getValue(int d)函数功能如下: 当d < -2时,值为abs(d); 当-2≤d<2 且d!=0时,值为d*...