phpunitを使ってTDDシリーズを実践してみる
銀行口座から始めましょう
phpunit がインストールされていると仮定します。
TDD (テスト駆動開発) の考え方を理解するために、簡単な銀行口座の例から始めます。
プロジェクト ディレクトリの下に 2 つのディレクトリ src
和test
,在src
下建立文件 BankAccount.php
,在test
目录下建立文件BankAccountTest.php
を作成します。
TDD の考え方によれば、最初にテストを書いてから本番コードを書くので、BankAccount.php
留空,我们先写BankAccountTest.php
。
それでは、実行して結果を見てみましょう。 phpunit を実行するコマンドラインは次のとおりです:
リーリー--bootstrap src/BankAccount.php
是说在运行测试代码之前先加载 src/BankAccount.php
,要运行的测试代码是test/BankAccountTest.php
。
特定のテストファイルを指定せずにディレクトリのみを指定した場合、phpunitは*Test.php
的文件。因为test
目录下只有BankAccountTest.php
ファイルと名前が一致するディレクトリ内のすべてのファイルを実行するため、
同じ結果が得られます。
リーリーテストがないため、警告エラーが発生します。
アカウントのインスタンス化
以下にテストを追加してみましょう。 TDD は、モジュールの機能をボトムアップで設計するのに役立つ設計手法であることに注意してください。テストを書くときは、ユーザーの視点から始めなければなりません。ユーザーが BankAccount
クラスを使用する場合、最初に何をしますか? BankAccount の新しいインスタンスである必要があります。したがって、最初のテストは インスタンス化 のテストです。
phpunit の実行が予想どおり失敗しました。
リーリー クラスの定義が見つかりませんでした。次に、本番コードを記述します。テストに合格させます。 src/BankAccount.php
(以下、ソースファイルと呼びます) に次の内容を入力します: BankAccount
类的定义,下面我们就要写生产代码。使测试通过。在src/BankAccount.php
リーリー
リーリー
次に、テストを追加してテストを失敗させる必要があります。新規口座を作成した場合、口座残高は0になります。そこで、 ステートメントを追加しました: assert
リーリー
value()
は のメンバー関数であることに注意してください。もちろん、この関数はまだ定義されていません。ユーザーとしては、value()
是BankAccount
的一个成员函数,当然这个函数还没有定义,作为使用者我们希望BankAccount
がこの関数を提供することを望んでいます。
phpunitを実行すると、結果は次のようになります:
リーリー結果は、BankAccount
并没有value()
にメンバー関数 value()
がないことがわかります。プロダクションコードを追加:
なぜ value()
直接返回0,因为测试代码中希望value()
は 0 を返す必要があるのでしょうか? TDD の原則は、テストに合格できる程度の冗長な製品コードを作成しないことです。
口座の入出金
phpunit を実行して渡した後、まず BankAccount
的实例化已经满足要求了,接下来,用户希望怎么使用BankAccount
呢?一定希望往里面存钱,嗯,希望BankAccount
のインスタンス化が要件を満たしていると仮定します。次に、ユーザーは
リーリー
口座の初期残高は0です。10元入金した場合、口座残高は当然10になります。 phpunit を実行すると、デポジット関数がまだ定義されていないため、テストは失敗します。リーリー
次にソースファイルにデポジット関数を追加します:リーリー
phpunit を再度実行すると、次の結果が得られます:リーリー
この時、入金機能で口座残高の操作を行っていないため、残高の初期値は0であり、入金機能実行後も0のままとなり、ユーザーが期待する動作ではありません。ユーザーが入金した金額を残高に追加する必要があります。
$value
,那么value
函数应该返回$value
残高を操作するには、残高をBankAccountのメンバー変数にする必要があります。この変数は外部から変更できないため、プライベート変数として定義されます。次に、プライベート変数
リーリー
deposit
函数传递负数,就相当于取钱了。
于是我们在测试代码的testDeposit
phpunitを実行するとテストに合格します。次に、ユーザーが他に何を必要としているのかを考えました。はい、お金を引き出します。お金を引き出すとき、この金額は口座残高から差し引かれます。
リーリー
phpunitを再度実行すると、テストが失敗しました。
リーリー
$value
これは、製品コードでは単に
リーリー
phpunitを再度実行すると、テストに合格します。新しいコンストラクター
BankAccount
对象时,可以传入一个值作为账户余额。于是我们在testNewAccount
次に、ユーザーは
testNewAccount
に追加します。 リーリー
phpunitを実行すると、結果は次のようになります: 🎜<code>1) BankAccountTest::testNewAccount Failed asserting that null matches expected 10.</code>
这时因为BankAccount
没有带参数的构造函数,因此new BankAccount(10)
会返回一个空对象,空对象的value()
函数自然返回的也是null。为了通过测试,我们在生产代码中增加带参数的构造函数。
<code>public function __construct($n){ $this->value = $n; }</code>
再运行测试:
<code>1) BankAccountTest::testNewAccount Missing argument 1 for BankAccount::__construct(), called in /home/wuchen/projects/jolly-code-snippets/php/phpunit/test/BankAccountTest.php on line 5 and defined /home/wuchen/projects/jolly-code-snippets/php/phpunit/src/BankAccount.php:5 /home/wuchen/projects/jolly-code-snippets/php/phpunit/test/BankAccountTest.php:5 2) BankAccountTest::testDeposit Missing argument 1 for BankAccount::__construct(), called in /home/wuchen/projects/jolly-code-snippets/php/phpunit/test/BankAccountTest.php on line 12 and defined /home/wuchen/projects/jolly-code-snippets/php/phpunit/src/BankAccount.php:5 /home/wuchen/projects/jolly-code-snippets/php/phpunit/test/BankAccountTest.php:12</code>
两个调用new BankAccount()
的地方都报告了错误,增加了带参数的构造函数,不带参数的构造函数又不行了。从c++/java
过渡来的同学马上想到增加一个默认的构造函数:
<code>public function __construct() { $this->value = 0; }</code>
但这样是不行的,因为php不支持函数重载,所以不能有多个构造函数。
怎么办?对了,我们可以为参数增加默认值。修改构造函数为:
<code>public function __construct($n = 0){ $this->value = $n; }</code>
这样调用 new BankAccount()
时,相当于传递了0给构造函数,满足了需求。
phpunit运行以下,测试通过。
这时,我们的生产代码为:
<code><?php class BankAccount { private $value; // default to 0 public function __construct($n = 0){ $this->value = $n; } public function value(){ return $this->value; } public function deposit($ammount) { $this->value += $ammount; } } ?></code>
总结
虽然我们的代码并不多,但是每一步都写得很有信心,这就是TDD的好处。即使你对php的语法不是很有把握(比如我),也可以对自己的代码很有信心。
用TDD的方式写程序的另一个好处,就是编码之前不需要对单个模块进行仔细的设计,可以在写测试的时候进行设计。这样开发出来的模块既可以满足用户需要,也不会冗余。
后面将会介绍 phpunit 的更多用法。
以上就介绍了用phpUnit入门TDD,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。