ホームページ >バックエンド開発 >PHPチュートリアル >PHP コードを作成するときに単体テストを行ったことがありますか?

PHP コードを作成するときに単体テストを行ったことがありますか?

WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWB
WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBオリジナル
2016-06-13 12:19:011167ブラウズ

PHP コードを書くときに単体テストを行ったことがありますか?

実は、最初は単体テストをしようと思っていましたが、時間が経つにつれて考えなくなりました。

PHP プログラミングを通じて技術分野の専門家になりたい場合、実際のスキルは PHP の外にあります。データベースに関する本を少なくとも 1 冊、XML に関する本を少なくとも 1 冊、単体テストに関する本を少なくとも 1 冊、ソフトウェア エンジニアリングに関する本を少なくとも 1 冊、データ構造とアルゴリズムに関する本を少なくとも 1 冊、*nix に関する本を少なくとも 1 冊読む必要があります。サーバーは少なくとも 1 冊の本、仏教経典、道経経、おそらく易経などを読み、読み続ける必要があります。

概念

単体テストを作成するには、いくつかの基本的な概念が必要です。 PHP ではこれらの概念は教えられません。

まず、Baidu 百科事典からいくつかの栄養を取り出してみましょう。

工場ではテレビを組み立てる前に各コンポーネントをテストします。これは単体テストです。

単体テストとは、ソフトウェア内のテスト可能な最小単位をチェックおよび検証することを指します。単体テストにおけるユニットの意味については、C言語では関数、Javaではクラス、グラフィカルではユニットというように、一般的には実情に応じて具体的な意味を判断する必要があります。ソフトウェアでは、ウィンドウまたはメニューを参照できます。一般に、ユニットとは、テスト対象として人為的に指定された最小の機能モジュールです。単体テストは、ソフトウェア開発中に実行される最低レベルのテスト作業であり、ソフトウェアの独立したユニットがプログラムの他の部分から分離されてテストされます。

単体テストはプログラマー自身によって完了し、最終的にはプログラマー自身が利益を得ます。プログラマーは、機能コードを作成する責任があり、また、独自のコードの単体テストを作成する責任もあります。単体テストを実行することは、このコードが期待どおりに動作することを証明することです。

-Baidu Encyclopedia

インストール

PHPUnit の現在の安定バージョンは 4.6 に達し、インターネット上の多くの姿勢が無効になりました。たとえば、配布方法は以前は Pear を使用してインストールされていましたが、現在は Phar パッケージまたは Composer に直接依存しています。

<code>wget https://phar.phpunit.de/phpunit.phar? chmod +x phpunit.phar? sudo mv phpunit.phar /usr/local/bin/phpunit? phpunit --version</code>
<code>{    "require-dev": {        "phpunit/phpunit": "4.6.*"    }}</code>

しかし、初心者にとってもう 1 つの重要な phpunit-skelgen はこのパッケージには含まれておらず、ダウンロード アドレスを見つけるのは困難です: https://phar.phpunit.de / phpunit-skelgen.phar

<code>wget https://phar.phpunit.de/phpunit-skelgen.pharchmod +x phpunit-skelgen.pharmv phpunit-skelgen.phar /usr/local/bin/phpunit-skelgen</code>

問題解決

開発プロセス中、ソフトウェアの内部構造に変更を加える必要があるとき、実際には、ソフトウェアに影響を与えずに変更を加えたいと考えます。可視性 動作を理解しやすく、変更しやすくするテスト スイートは、いわゆるリファクタリングを安全に実行するために非常に役立ちます。そうしないと、再編プロセス中に気付かないうちにシステムが壊れてしまう可能性があります。

単体テストを使用して、元の動作が実際に維持され、リファクタリングの変換ステップ中にバグが導入されていないことを確認すると、次のような状況がプロジェクトのコーディングと設計の改善に役立ちます。

  • すべての単体テストが正しく実行されます。

  • コードは、その設計原則を伝えます。

  • コードに冗長性はありません。

  • コードに含まれるクラスとメソッドの数は最小限に抑えてください。

システムに新しい機能を追加する必要がある場合は、まずその機能のテストを作成します。その後、テストが正常に実行されれば開発は完了です。

利点

1. 検証動作です。

プログラム内のすべての機能は、その正確性を検証するためにテストされます。今後の開発をサポートします。開発の後半でも、重要なものが壊れることを心配することなく、簡単に機能を追加したり、プログラムの構造を変更したりすることができます。また、コードのリファクタリングに対する保護も提供します。これにより、より自由にプログラムを改良することが可能になります。

2. これは設計上の動作です。

単体テストを作成すると、呼び出し側の観点から観察して考えることができます。特に、テストを最初に書く (テストファースト) と、呼び出しやすくテストしやすいようにプログラムを設計する必要があります。つまり、ソフトウェアを切り離す必要があります。

3. 文書を書く行為です。

単体テストは、関数またはクラスがどのように使用されるかを示す貴重なドキュメントです。このドキュメントはコンパイル可能で実行可能であり、常にコードと同期して最新の状態に保たれます。

4. それは退行的です。

自動化された単体テストにより、コードのリグレッションを回避できます。作成後、いつでもどこでもすぐにテストを実行できます。

練習

いつテストしますか?

単体テストは早ければ早いほど良いですか?

エクストリーム プログラミング (略して XP) は、最初にテスト コードを作成してから開発する TDD を重視します。実際の仕事において、重要なのは効率と快適さです。

経験上、最初に製品関数のフレームワークを記述し、次にテスト関数を記述し、製品関数の関数のテスト ケースを記述し、次に製品関数のコードを記述して、各関数のテストを実行します。ポイントを書いて、いつでもテスト ケースを追加します。

製品関数を先に書くいわゆるフレームワークとは、最初に関数の空の実装を書き、戻り値があれば直接適切な値を返すというもので、コンパイルが通った後にテストコードを書きます。この時点で、関数名、パラメータリスト、戻り値の型を決定する必要があり、作成されたテストコードは将来変更する必要が少なくなります。

由谁测试?

单元测试与其他测试不同,单元测试可看作是编码工作的一部分,应该由程序员完成,也就是说,经过了单元测试的代码才是已完成的代码,提交产品代码时也要同时提交测试代码。测试部门可以作一定程度的审核。

请一定要看完官方文档:

要进行充分的单元测试,一般来说应专门编写测试代码,并与产品代码隔离。但对于初学者来说,总是会有点别扭,因为感觉额外做了很多工作,影响开发效率。其实像phpunit也是支持在类方法的文档注释块(docblock)中使用 @test 标注将其标记为测试方法的。这样,彻底贯彻我们代码即文档的思想。

<code><?phpclass Calculator{    /**     * @assert (0, 0) == 0     * @assert (0, 1) == 1     * @assert (1, 0) == 1     * @assert (1, 1) == 2     * @assert (1, 2) == 4     */    public function add($a, $b)    {        return $a + $b;    }}</code>

现实难题

我们到底要测什么?算法?一般很少。

大都是在编写业务功能。而且大多数是基于数据库的系统开发。这是我们实施PHP单元测试最大的难点所在。需要整合PHPUnit的DBUnit测试,也就是一开始就得学习DBUnit的知识。

在各种编程语言中,许多入门与中级的单元测试范例都暗示着这样一种信息:很容易用简单的测试来对应用程序的逻辑进行测试。但是对于以数据库为中心的应用程序而言,这与现实相去甚远。一旦开始使用诸如 Wordpress、TYPO3、或 Symfony(配合 Doctrine 或 Propel)之类的东西,就很容易在用 PHPUnit 时碰到超多问题:正是由于这些库和数据库之间实在耦合的太紧密了。

你大概会在日常工作面对的项目中经历这一幕。你打算把你那或生疏或纯熟的 PHPUnit 技能用到工作中去,结果被以下问题之一卡住了:

  • 待测方法执行了一个相当大的 JOIN 操作,并且得到的数据用于计算某些重要的结果。
  • 业务逻辑中混合执行了 SELECT、INSERT、UPDATE 和 DELETE 语句。
  • 为了给待测方法建立合理的初始数据,需要在两个以上(可能远超过)表里设置测试数据。

DbUnit

DbUnit扩展大大简化了为测试设置数据库的操作,并且可以在对数据执行了一系列操作之后验证数据库的内容。

DbUnit所支持的供应商

DbUnit 目前支持 MySQL、PostgreSQL、Oracle 和 SQLite。通过集成 Zend Framework 或 Doctrine 2,也可以访问其他数据库系统,比如 IBM DB2 或者 Microsoft SQL Server。

数据库测试的难点

为什么所有单元测试的范例都不包含数据库交互?这里有个很好的理由:这类测试的建立和维护都很复杂。对数据库进行测试时,需要考虑以下这些变数:

  • 数据库和表
  • 向表中插入测试所需要的行
  • 测试运行完毕后验证数据库的状态
  • 每个新测试都要清理数据库

许多数据库 API,比如 PDO、MySQLi 或者 OCI8,都十分繁琐且书写起来十分冗长,因此,手工进行这些步骤绝对是噩梦。

测试代码应当尽可能简短精确,这有若干原因:

  • 你不希望因为生产代码的小变更而需要对测试代码进行数量可观的修改。

  • 你希望在哪怕好几个月以后也能轻松地阅读并理解测试代码。

另外,必须认识到,对于代码而言,本质上来说数据库是全局输入变量。测试套件中的两个不同的测试可能是运行在同一个数据库上的,并且可能把数据重用好多次。一个测试中出现的失败很容易影响到后继测试的结果,从而让整个测试过程变得非常艰难。前面提到的清理步骤对于解决“数据库是全局输入”的问题是非常重要的。

DbUnit 以一种优雅的方式来帮助简化数据库测试中的所有这些问题。

PHPUnit 无法帮你解决的问题是,相对于不使用数据的测试而言,数据库测试是非常慢的。随着数据库交互规模的增大,运行测试可能需要耗费可观的时间。然而,只要保持每个测试所使用的数据量较小并且尽可能用非数据库测试来对代码进行测试,即使很大的测试套件也能轻松在一分钟内跑完。

数据库测试的四个阶段

Gerard Meszaros 在他的书《xUnit 测试模式》中列出了单元测试的四个阶段:

  • 建立基架(fixture)
  • 执行被测系统
  • 验证结果
  • 拆除基架(fixture)

什么是基架(fixture)?

<code>基架(fixture)是对开始执行某个测试时应用程序和数据库所处初始状态的描述。</code>

对数据库进行测试至少要处理建立与拆除的步骤,在其中完成清理工作,并将所需的基架数据写入表内。然而对于数据库扩展模块而言,在数据库测试中有很好的理由将这四个步骤还原成类似下面这样的工作流程,这个流程对于每个测试都会完整执行:

  1. 清理数据库

由于总是会有某个测试运行在并不确定表中是否有数据的数据库上,PHPUnit 在所有指定表上执行 TRUNCATE 操作来把它们清空。

  1. 建立基架

PHPUnit 随后将迭代所有指定的基架数据行并将其插入到对应的表里。

3–5. 运行测试、验证结果、并拆除基架

在所有数据库都完成重置并加载好初始状态后,PHPUnit 才会执行实际的测试。这个部分的测试代码完全不需要数据库扩展模块的参与,可以随意测试任何想要测试的内容。

在测试中,验证的目的可以使用一个名为 assertDataSetsEqual() 的特殊断言来实现。当然,这完全是可选的。

一些术语

  • 单元测试
  • 集成测试
  • 回归测试
  • 测试用例
  • 断言
  • 基架Fixture
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。