簡單的存根

有時,有一些程式碼難以測試,例如訪問資料庫或與使用者互動。你可以刪除程式碼部分,以便測試其餘程式碼。

讓我們從一個提示使用者的類開始。為簡單起見,它只有兩個方法,一個實際上提示使用者(將由所有其他方法使用)和我們要測試的方法,它提示和過濾掉只有是和沒有答案。請注意,此程式碼過於簡單化以用於演示目的。

class Answer
{
    // prompt the user and check if the answer is yes or no, anything else, return null
    public function getYesNoAnswer($prompt) {

        $answer = $this->readUserInput($prompt);

        $answer = strtolower($answer);
        if (($answer === "yes") || ($answer === "no")) {
            return $answer;
        } else {
            return null;
        }

    }

    // Simply prompt the user and return the answer
    public function readUserInput($prompt) {
        return readline($prompt);
    }

}

要測試 getYesNoAnswer,需要刪除 readUserInput 以模仿使用者的答案。

class AnswerTest extends PHPUnit_Framework_TestCase
{

    public function test_yes_no_answer() {

        $stub = $this->getMockBuilder(Answer::class)
                ->setMethods(["readUserInput"])
                ->getMock();

        $stub->method('readUserInput')
            ->will($this->onConsecutiveCalls("yes","junk"));

        // stub will return "yes"
        $answer = $stub->getYesNoAnswer("Student? (yes/no)");
        $this->assertSame("yes",$answer);

        // stub will return "junk"
        $answer = $stub->getYesNoAnswer("Student? (yes/no)");
        $this->assertNull($answer);

    }

}

第一行程式碼建立存根,它使用 getMockBuilder 而不是 createMockcreateMock 是使用預設值呼叫 getMockBuilder 的快捷方式。其中一個預設設定是刪除所有方法。對於這個例子,我們想測試 getYesNoAnswer,所以它不能被刪除。getMockBuilder 呼叫 setMethods 來請求只刪除 readUserInput

第二行程式碼建立了存根行為。它會截斷 readUserInput 方法並在後續呼叫時設定兩個返回值,yes 後跟 junk

第三行和第四行程式碼測試 getYesNoAnswer。第一次,假人回答並且測試的程式碼正確地返回,因為它是有效的選擇。第二次,假人響應垃圾,測試的程式碼正確返回 null。