如何提升 PHP 代碼的質量?第三:端到端 / 集成測試

在本系列的最後一部分,是時候設置端到端 / 集成測試環境,並確保咱們已經準備好檢查咱們工做的質量。php

在本系列的前幾部分中,咱們創建了一個構建工具,一些靜態代碼分析器,並開始編寫單元測試。html

爲了使咱們的測試堆棧更完整,有一些測試能夠檢查你的代碼是否在真實環境中運行,以及它是否能在更復雜的業務場景中運行良好。laravel

在這裏,咱們能夠使用爲行爲驅動開發構建的工具——官方 PHP 的 Cucumber 實現——Behat。咱們能夠經過運行如下代碼來安裝它:git

$ php composer.phar require --dev behat/behat

 

增長一個目標到 build.xml(在本文的第一部分中描述了 Phing 設置)web

<target name="behat">   <exec executable="bin/behat" passthru="true" checkreturn="true"/></target>…<target name="run" depends="phpcs,phpcpd,phan,phpspec,behat"/>

 

而後,你應該爲文件 features/price.feature 的測試建立一個規範。sql

Feature: Price Comparison  In order to compare prices  As a customer  I need to break the currency barrier   Scenario: Compare EUR and PLN    Given I use nbp.pl comparator    When I compare 「100EUR」 and 「100PLN」    Then It should r

 

eturn some result

這個測試場景很是容易閱讀,而且應該給你一個關於該特性應該如何工做的良好印象。不幸的是,計算機一般並不真正理解人類語言,因此如今是爲每一步編寫代碼的時候了。shell

你能夠經過運行 ./bin/behat-init 來生成它的代碼模板。它應該會建立一個這樣的類:bootstrap

1 //features/bootstrap/FeatureContext.php use Behat\Behat\Context\SnippetAcceptingContext;use Behat\Gherkin\Node\PyStringNode;use Behat\Gherkin\Node\TableNode;class FeatureContext implements SnippetAcceptingContext{    /**     * Initializes context.     */    public function __construct()    {    }}

 

而後你能夠執行:服務器

1 $ bin/behat --dry-run --append-snippets

 

Behat 將自動爲場景中定義的每一個步驟建立函數。
如今你能夠經過填充函數的主體來開始實現真正的檢查:架構

// features/bootstrap/FeatureContext.php <?phpuse Behat\Behat\Context\Context;use Domain\Price;use Domain\PriceComparator;use Infrastructure\NBPPriceConverter; /*** Defines application features from the specific context.*/class FeatureContext implements Context{   /** @var PriceComparator */   private $priceComparator;    /** @var int */   private $result;    /**    * Initializes context.    *    * Every scenario gets its own context instance.    * You can also pass arbitrary arguments to the    * context constructor through behat.yml.    */   public function __construct()   {   }    /**    * @Given I use nbp.pl comparator    */   public function iUseNbpPlComparator()   {       $this->priceComparator = new PriceComparator(new NBPPriceConverter());   }    /**    * @When I compare :price1 and :price2    */   public function iCompareAnd($price1, $price2)   {       preg_match('/(\d+)([A-Z]+)/', $price1, $match1);       preg_match('/(\d+)([A-Z]+)/', $price2, $match2);       $price1 = new Price($match1[1], $match1[2]);       $price2 = new Price($match2[1], $match2[2]);       $this->result = $this->priceComparator->compare($price1, $price2);   }    /**    * @Then It should return some result    */   public function itShouldReturnSomeResult()   {       if (!is_int($this->result)) {           throw new \DomainException('Returned value is not integer');       }   }}

 

最後,使用 ./bin/phing 運行全部的測試。你應該獲得如下結果:

Buildfile: /home/maciej/workspace/php-testing/build.xmlMyProject > phpcs: MyProject > phpcpd: phpcpd 4.0.0 by Sebastian Bergmann.0.00% duplicated lines out of 103 total lines of code. Time: 17 ms, Memory: 4.00MB MyProject > phan: MyProject > phpspec: /  skipped: 0%  /  pending: 0%  / passed: 100%  /  failed: 0%   /  broken: 0%   /  3 examples2 specs3 examples (3 passed)15ms MyProject > behat: Feature: Price Comparison In order to compare prices As a customer I need to break the currency barrier  Scenario: Compare EUR and PLN          # features/price.feature:6   Given I use nbp.pl comparator        # FeatureContext::iUseNbpPlComparator()   When I compare "100EUR" and "100PLN" # FeatureContext::iCompareAnd()   Then It should return some result    # FeatureContext::itShouldReturnSomeResult()1 scenario (1 passed)3 steps (3 passed)0m0.01s (9.13Mb) MyProject > run: BUILD FINISHED Total time: 1.1000 second

 

正如你所看到的,Behat 準備了一份很好的報告,說明咱們的應用程序作了什麼,結果是什麼。下一次,當項目經理詢問你在測試中涉及到哪些場景時,你能夠給他一個 Behat 輸出!

1 測試的結構

每一個測試都包括:

  • 對該場景的一些準備,用「Given」部分表示
  • 「When」部分所涵蓋的一些動做
  • 一些檢查被標記爲「Then」部分

每一個部分均可以包含多個與「And」關鍵字鏈接的步驟:

Scenario: Compare EUR and PLN    Given nbp.pl comparator is available    And I use nbp.pl comparator    When I compare "100EUR" and "100PLN"    And I save the result    Then It should return some result    And the first amount should be greater

 

2 上下文

Behat 容許你爲你的測試定義多個上下文。這意味着你能夠將步驟代碼分割成多個類,並從不一樣的角度去測試你的場景。

你能夠例如:爲 web 上下文編寫代碼,它將使用你的應用程序 HTTP 控制器運行你的測試步驟。你還能夠建立「domain」上下文,它將只使用 PHP API 調用來運行你的業務邏輯。經過這種方式,你能夠單獨地測試業務邏輯集成,從端到端應用程序測試。

關於如何在 Behat 創建許多上下文的更多信息,請參考  的文檔。

3 我是如何使用 Behat 的?

正如一開始所提到的,你能夠使用 Behat 進行集成測試。一般狀況下,你的代碼依賴於一些外部的第三方系統。當咱們在第 2 部分中編寫單元測試時,咱們老是假設外部依賴關係像預期的那樣工做。使用 Behat,你能夠編寫測試場景,它將自動運行你的代碼,並檢查它是否正確地使用真實場景的服務。

最重要的是,Behat 對於測試系統使用的複雜的端到端場景很是有用。它容許你隱藏在一個可讀性的名字後面運行測試步驟所需的複雜代碼,並編寫一我的人都能理解的場景。

總結

從以上的文章中,你已經學習瞭如何在你的項目中設置六個有用的工具:

  • PHing 用於運行你的構建
  • PHPCS 用於自動檢查代碼格式
  • PHPCPD 用於檢測重複代碼的
  • Phan 用於高級靜態代碼分析
  • PHPSpec 用於單元測試
  • Behat 用於端到端和集成測試

如今,你能夠向 git 提交鉤子添加 ./bin/phing,並設置持續集成來運行每一個提交的測試。

是否是忽然之間,沒有什麼能阻止你寫出高質量的 PHP 代碼!

Well done!

不少PHPer在進階的時候總會遇到一些問題和瓶頸,業務代碼寫多了沒有方向感,不知道該從那裏入手去提高,對此我整理了一些資料,包括但不限於:分佈式架構、高可擴展、高性能、高併發、服務器性能調優、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql優化、shell腳本、Docker、微服務、Nginx等多個知識點高級進階乾貨須要的能夠免費分享給你們,須要的加羣(點擊→)677079770

推薦閱讀:

教你如何提升 PHP 代碼的質量

 

如何提升 PHP 代碼的質量?第二部分 單元測試

相關文章
相關標籤/搜索