PHPunit单元测试的利器

2015-04-23  付民 

http://www.phpunittest.com/?p=25

PHPUnit是PHP的单元测试框架。单元测试在软件开发中越来越受到重视,测试先行编程、极限编程和测试驱动开发在实践中被广泛。利用单元测试,也可以实现契约式设计。


接下来,我们通过一个例子说明如何利用PHPUnit来实践测试驱动开发。

假设我们需要编写一个银行账户的功能:BankAccount。该功能用于设置银行账户收支,存取现金,必须确保:

  • 银行账户初始化时余额为0。

  • 余额不能为负数。

在编写代码之前,我们先为BankAccout类编写测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
require_once 'BankAccount.php';class BankAccountTest extends PHPUnit_Framework_TestCase{    protected $ba;    protected function setUp()
    {        $this->ba = new BankAccount;
    }    public function testBalanceIsInitiallyZero()
    {        $this->assertEquals(0, $this->ba->getBalance());
    }    public function testBalanceCannotBecomeNegative()
    {        try {            $this->ba->withdrawMoney(1);
        }        catch (BankAccountException $e) {            $this->assertEquals(0, $this->ba->getBalance());            return;
        }        $this->fail();
    }    public function testBalanceCannotBecomeNegative2()
    {        try {            $this->ba->depositMoney(-1);
        }        catch (BankAccountException $e) {            $this->assertEquals(0, $this->ba->getBalance());            return;
        }        $this->fail();
    }
}


现在我们编写为了让第一个测试testBalanceIsInitiallyZero()通过所需要的代码:

1
2
3
4
class BankAccount{    protected $balance = 0;    public function getBalance()
    {        return $this->balance;
    }
}

现在第一个测试可以通过了,第二个还不行:

1
2
3
4
5
phpunit BankAccountTest
PHPUnit 3.7.0 by Sebastian Bergmann.
 
.
Fatal error: Call to undefined method BankAccount::withdrawMoney()

为了让第二个测试通过,我们需要实现withdrawMoney()、depositMoney()和setBalance()方法。这些方法在违反约束条件时,会抛出一个BankAccountException。

1
2
3
4
5
6
7
8
9
10
11
12
class BankAccount{    protected $balance = 0;    public function getBalance()
    {        return $this->balance;
    }    protected function setBalance($balance)
    {        if ($balance >= 0) {            $this->balance = $balance;
        } else {            throw new BankAccountException;
        }
    }    public function depositMoney($balance)
    {        $this->setBalance($this->getBalance() + $balance);        return $this->getBalance();
    }    public function withdrawMoney($balance)
    {        $this->setBalance($this->getBalance() - $balance);        return $this->getBalance();
    }
}

现在第二个测试也能通过啦~

1
2
3
4
5
6
7
phpunit BankAccountTest
PHPUnit 3.7.0 by Sebastian Bergmann.
 
...Time: 0 seconds
 
 
OK (3 tests, 3 assertions)

你也可以使用契约式设计的风格,只需使用PHPUnit_Framework_Assert类提供的静态断言方法编写契约条件。下面例子中,如果断言不成立,就会抛出一个PHPUnit_Framework_AssertionFailedError。这种方式可以增加你的代码的可读性。但是这也意味着你需要PHPUnit会成为你的运行时依赖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class BankAccount{    private $balance = 0;    public function getBalance()
    {        return $this->balance;
    }    protected function setBalance($balance)
    {
        PHPUnit_Framework_Assert::assertTrue($balance >= 0);        $this->balance = $balance;
    }    public function depositMoney($amount)
    {
        PHPUnit_Framework_Assert::assertTrue($amount >= 0);        $this->setBalance($this->getBalance() + $amount);        return $this->getBalance();
    }    public function withdrawMoney($amount)
    {
        PHPUnit_Framework_Assert::assertTrue($amount >= 0);
        PHPUnit_Framework_Assert::assertTrue($this->balance >= $amount);        $this->setBalance($this->getBalance() - $amount);        return $this->getBalance();
    }
}
468°/4684 人阅读/0 条评论 发表评论

登录 后发表评论