Неуспешен тест за меко твърдение и фалшиви методи

Следвам този урок: http://jtreminio.com/2013/03/unit-testing-tutorial-part-5-mock-methods-and-overriding-constructors/ . Страхотен урок, за да научите как работи PHPUnit.

Но не мога да разбера, защото тестът не мина.

Провалът е:

Method was expected to be called 1 times, actually called 0 times.

В тази част от кода:

        $badCode->expects($this->once())
            ->method('checkPassword')
            ->with($password);

Но това не е възможно, защото следващото меко твърдение се изпълнява в метода checkPassword и преминава теста.

        $badCode->expects($this->once())
            ->method('callExit');

Не успява, защото е макет метод и поведението е различно? Или кодът е грешен?

Прилагам всички файлове за лесно разбиране, това е малък пример.

Конзола

PHPUnit 3.7.18 by Sebastian Bergmann.

FYOU SHALL NOT PASS............

Time: 0 seconds, Memory: 6.00Mb

There was 1 failure:

1) phpUnitTutorial\Test\BadCodeTest::testAuthorizeExitsWhenPasswordNotSet
Expectation failed for method name is equal to <string:checkPassword> when invoked 1 time(s).
Method was expected to be called 1 times, actually called 0 times.


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

BadCode.php

<?php

namespace phpUnitTutorial;

class BadCode
{
    protected $user;

    public function __construct(array $user)
    {
        $this->user = $user;
    }

    public function authorize($password)
    {
        if ($this->checkPassword($password)) {
            return true;
        }

        return false;
    }

    protected function checkPassword($password)
    {
        if (empty($user['password']) || $user['password'] !== $password) {
            echo 'YOU SHALL NOT PASS';
            $this->callExit();
        }

        return true;
    }

    protected function callExit()
    {
        exit;
    }
}

BadCodeTest.php

<?php

namespace phpUnitTutorial\Test;

class BadCodeTest extends \PHPUnit_Framework_TestCase
{
    public function testAuthorizeExitsWhenPasswordNotSet()
    {
        $user = array('username' => 'jtreminio');
        $password = 'foo';

        $badCode = $this->getMockBuilder('phpUnitTutorial\BadCode')
            ->setConstructorArgs(array($user))
            ->setMethods(array('callExit'))
            ->getMock();

        $badCode->expects($this->once())
            ->method('checkPassword')
            ->with($password);

        $badCode->expects($this->once())
            ->method('callExit');

        $this->expectOutputString('YOU SHALL NOT PASS');

        $badCode->authorize($password);
    }
}

Някой може ли да ми помогне? Благодаря!

Актуализация

Авторът на блога актуализира урока с решението. Не може да прави никакви твърдения срещу макетни методи, само мъничета.

BadCode.php

<?php

namespace phpUnitTutorial;

class BadCode
{
    protected $user;

    public function __construct(array $user)
    {
        $this->user = $user;
    }

    public function authorize($password)
    {
        if ($this->checkPassword($password)) {
            return true;
        }

        return false;
    }

    protected function checkPassword($password)
    {
        if (empty($this->user['password']) || $this->user['password'] !== $password) {
            echo 'YOU SHALL NOT PASS';
            $this->callExit();
        }

        return true;
    }

    protected function callExit()
    {
        exit;
    }
}

BadCodeTest.php

<?php

namespace phpUnitTutorial\Test;

class BadCodeTest extends \PHPUnit_Framework_TestCase
{
    public function testAuthorizeExitsWhenPasswordNotSet()
    {
        $user = array('username' => 'jtreminio');
        $password = 'foo';

        $badCode = $this->getMockBuilder('phpUnitTutorial\BadCode')
            ->setConstructorArgs(array($user))
            ->setMethods(array('callExit'))

        $badCode->expects($this->once())
            ->method('callExit');

        $this->expectOutputString('YOU SHALL NOT PASS');

        $badCode->authorize($password);
    }
}

person Sangar82    schedule 04.04.2013    source източник


Отговори (2)


автор тук - избърках тази част и AppFog (моят хост) има проблеми с безплатни акаунти (моя), така че не мога да го актуализирам в момента.

Освен това, да, трябва да е $this->user в checkPassword()

person Juan Treminio    schedule 04.04.2013
comment
Добре, чакам решението! Много благодаря! - person Sangar82; 04.04.2013
comment
Хей @Sangar82 кодът е актуализиран. Извинения за объркването! - person Juan Treminio; 04.04.2013
comment
Вие сте изтрили $badCode-›expects($this-›once())-›method('checkPassword')-›with($password); Но защо? Изглежда, че това трябва да работи, но не разбирам, защото се проваля на теста, преди да изтриете тези редове - person Sangar82; 05.04.2013
comment
@Sangar82 Направих грешка и забравих, че не можете да правите никакви твърдения срещу макетни методи, само мъничета. Мисля, че разрешаването на някои ->expects() на mocks би било много полезно. - person Juan Treminio; 05.04.2013
comment
Благодаря за отговора и се надявам да следвате урока за модулно тестване. Чудесна работа! - person Sangar82; 05.04.2013

Липсва ви метод в setMethods:

->setMethods(array('callExit'))

Трябва да добавите и checkPassword, ако искате да проверите дали се извиква.

person Alain Tiemblo    schedule 04.04.2013
comment
И аз си помислих това (и може да е правилно), но примерът все още няма да работи - person hek2mgl; 04.04.2013
comment

Моето приложение е нещо като приложение за речник, когато търся една дума, то показва самата дума, произношение, дефиниция и бутон за споделяне във facebook. Искам да знам как да поставя тази дума в полето за споделяне на съобщения във Facebook.

- person Sangar82; 04.04.2013
comment
@Sangar82 Да, прав си. Вече научих... Благодаря за урока. Сега разбирам кода ви и изглежда добре. Имате нужда от callExit() като мъниче, тъй като в противен случай би приключил набора от тестове (с помощта на изход). Ще са необходими по-задълбочени тестове. Коя версия на PHPUnit използвате? Но трябва едно нещо (въпреки че) то не принадлежи пряко към проблема: Използвайте $this->user вместо $user в checkPassword() - person hek2mgl; 04.04.2013
comment
@hek2mgl Използвам 3.7.18. Името на класа е BadCode, не очаквайте много повече от примера, но обяснява много добре разликата между метода на пъна и макетния метод. Ако премахнете тези линии, тестът преминава. Изглежда всичко правилно, но не преминава теста и това ме заинтригува - person Sangar82; 04.04.2013