在PHP中使用Mockery進行測試驅動開發(TDD) - 上


測試驅動開發網上也談了很多了,PHP方面的文章也有一些,在百度和Google里搜,好像沒有看到幾篇談用Mock(偽裝對象)的技術的,這里寫篇文章講講。

先過一下測試驅動開發的基本理念:就是先寫測試用例(一般這個測試用例都是自動化的單元測試用例,便於快速回滾執行),然后通過逐步修復測試用例的方法補齊產品代碼,最后測試用例修復完畢后,產品也就寫完了。

從我自己的實踐中,我認為在類庫開發的時候使用測試驅動開發技術是一個很好的方案,理由如下:
能夠寫出測試用例,即說明對問題域已經有一個清晰的了解,
節省了寫文檔的時間,測試用例就是類庫調用的示例代碼了。
代碼質量有保證,因為寫類庫的過程就是修復測試用例的過程,所以測試用例修復完畢后類庫也就寫完了。
便於估時,估計類庫開發時間的問題就簡化成估計修復測試用例的時間了,相對於來說估時容易一些。

我們以編寫一個字符串轉數字的函數為例講解測試驅動開發的理念,再引入Mock技術。在開始之前,需要安裝PHPUnit和Mockery庫(本文不使用PHPUnit自帶的Mock庫):

# 安裝PHPUnit
pear config-set auto_discover 1
pear install pear.phpunit.de/PHPUnit

# 安裝Mock庫
sudo pear channel-discover pear.survivethedeepend.com
sudo pear channel-discover hamcrest.googlecode.com/svn/pear
sudo pear install --alldeps deepend/Mockery

那從測試驅動開發的理念來做的話,我們先寫測試用例 – parseinttest.php:

<?
    class ParseIntTest extends PHPUnit_Framework_TestCase {
        public function testParseIntBasic() {
            $v = parse_int("12345");
            $this->assertEquals(12345, $v);

            $v = parse_int("-12345");
            $this->assertEquals(-12345, $v);

        /*
            $v = parse_int("abcd");
            $this->assertEquals(0, $v);

            $v = parse_int("0xab12");
            $this->assertEquals(0xab12, $v);

            $v = parse_int("01b");
            $this->assertEquals(1, $v);
        */
        }
    }
?>

上面的代碼里,我們通過單元測試用例指定了要實現的函數parse_int的需求,即可以解析整數、帶符號的整數等,又因為時間和資源的限制,那我們去掉了對十六進制和二進制的支持。

運行下面的命令執行測試用例:

phpunit --verbose parseinttest

因為這個時間沒有任何代碼,所以得到期望的錯誤 – PHPUnit告訴我們找不到parse_int這個函數:
PHPUnit 3.6.12 by Sebastian Bergmann.

PHP Fatal error:  Call to undefined function parse_int() in /var/www/pmdemo/parseinttest2.php on line 6

那我們先建一個空的parse_int函數 – parseint.php:

<?
    function parse_int($str) {
        return 0;
    }
?>

上面的代碼里我們先不實現函數parse_int的任何邏輯,再運行測試用例,得到:

shiyimin@ubuntu:/var/www/pmdemo$ phpunit --verbose parseinttest
PHPUnit 3.6.12 by Sebastian Bergmann.

F

Time: 0 seconds, Memory: 2.75Mb

There was 1 failure:

1) ParseIntTest::testParseIntBasic
Failed asserting that 0 matches expected 12345.

/var/www/pmdemo/parseinttest.php:7

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.

從上面紅色高亮顯示出來的錯誤消息,我們知道是測試用例里的第一個判斷沒有通過,即下面的判斷語句沒有執行成功:

$this->assertEquals(12345, $v);

這是因為我們的parse_int函數總是返回0這個值,發現了這個錯誤,我們來補齊這個邏輯以修復測試用例:

parseint.php

<?
    function parse_int($str) {
        $result = 0;
    $i = 0;    

    for ( $i = 0; $i < strlen($str); ++$i ) {    
        $result *= 10;
        $result += $str[$i] - '0';
    }

    return $result;
    }
?>

再次運行測試用例:
shiyimin@ubuntu:/var/www/pmdemo$ phpunit --verbose parseinttest
PHPUnit 3.6.12 by Sebastian Bergmann.

F

Time: 0 seconds, Memory: 2.75Mb

There was 1 failure:

1) ParseIntTest::testParseIntBasic
Failed asserting that 12345 matches expected -12345.

/var/www/pmdemo/parseinttest.php:10

FAILURES!
Tests: 1, Assertions: 2, Failures: 1.

從上面的結果可以看出,第一個測試用例已經修復了,現在是在處理帶符號的字符串時,發生了問題,繼續修復代碼:

parseint.php

<?
    function parse_int($str) {
        $result = 0;
    $i = 0;
    $neg = 1;
        
        if ( $str[0] == '-' ) { 
        $neg = -1;
    }

    for ( $i = 0; $i < strlen($str); ++$i ) {    
        $result *= 10;
        $result += $str[$i] - '0';
    }

    return $result * $neg;
    }
?>

再運行測試用例:
shiyimin@ubuntu:/var/www/pmdemo$ phpunit --verbose parseinttest
PHPUnit 3.6.12 by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 2.75Mb

OK (1 test, 2 assertions)

好了,這次所有測試用例都通過了,那我們的產品代碼的實現也告一段落了,當然文章為了講解方便,上面的代碼並不是一個完整的實現,例如它就無法處理字符串“+12345”的情形。

下篇文章講解如何在PHPUnit里應用Mock技術。

本文由知平軟件施懿民編寫,請關注我們的微博


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM