Как смоделировать аргумент, который возвращает новый класс в PHPUnit? - PullRequest
1 голос
/ 08 июня 2011

У меня проблема с такой строкой кода:

$user->has('roles', ORM::factory('role', array('name' => 'unverified')))

Я могу посмеяться над первым аргументом, но могу только утверждать, что 2-й аргумент возвращает класс. В некоторых классах я многократно использую has, и мне нужно правильно их протестировать. Чтобы было ясно, я должен подтвердить, что «непроверенный» был передан фабричному методу второго аргумента. Любая помощь очень ценится.

Класс, который я тестирую:

<?php
/**
 * Policy class to determine if a user can upload a file.
 */
class Policy_File_Upload extends Policy
{
    const NOT_LOGGED_IN = 1;
    const NOT_VERIFIED = 2;

    public function execute(Model_ACL_User $user, array $extra = NULL)
    {
        if ($user->can('login'))
        {
            return self::NOT_LOGGED_IN;
        }
        elseif ($user->has('roles', ORM::factory('role', array('name' => 'unverified'))))
        {
            return self::NOT_VERIFIED;
        }

        return TRUE;
    }
}

и соответствующий тест:

public function test_guest()
{
    // User mock
    $user = $this->getMock('Model_User', array('can', 'has'), array(), '', FALSE);
    $user->expects($this->any())->method('can')->with('login')->will($this->returnValue(TRUE));
    $user->expects($this->any())->method('has')->with('roles', $this->logicalOr
    (

    ))
    ->will($this->returnCallback(array($this, 'roles')));


    $policy = new Policy_File_Upload;

    $this->assertSame(Policy_File_Upload::NOT_VERIFIED, $policy->execute($user));
}

Ответы [ 3 ]

2 голосов
/ 08 июня 2011

Вы всегда можете пройти управляемый данными маршрут подготовки тестовых данных для каждого случая и проверить результат вызова функции.В конце концов, вас не очень заботит, что 'unverified' передается ORM::factory(), а скорее, что правильный результат получается из execute() на основе входных данных.

Проверка деталей реализации делаеттест хрупкий и трудный для написания.Если вместо этого вы можете проверить результаты, ваши тесты не будут нарушены, когда вы измените способ получения результата.Сбор данных для всех ваших сценариев использования может занять больше времени, но, как правило, его можно разделить между тестами.

1 голос
/ 08 июня 2011

На самом деле вы можете выполнить проверку параметров, передаваемых имитирующим методам, используя захват параметров в Фаговой среде для фейков для PHP.

public function test_guest()
{
    // User mock
    $user = Phake::mock('Model_User');
    when($user)->can('login')->thenReturn(FALSE);
    when($user)->has('roles', $this->anything())->thenGetReturnByLambda(array($this, 'roles'));

    $policy = new Policy_File_Upload;

    $this->assertSame(Policy_File_Upload::NOT_VERIFIED, $policy->execute($user));

    Phake::verify($user)->has('roles', Phake::capture($factoriedRole));

    $this->assertEquals('unverified', $factoriedRole->get('name'));
}

В этом примере предполагается, чточто у вас есть возможность проверить имя в $ factoriedRole, очевидно, что этот кусок нужно менять в зависимости от того, как работает этот стек ORM.

Небольшое замечание, я согласен с edorian относительно статики.Если возможно, я бы всегда предпочел переделать ваш код, чтобы он не требовал статики, но иногда это невозможно, и в этом случае это работоспособное решение.

Phake Github Page

Документация Phake по захвату параметров

1 голос
/ 08 июня 2011

Чтобы было ясно, я должен подтвердить, что "непроверенный" был передан в фабричный метод 2-го аргумента.

<?php

public function execute(Model_ACL_User $user, array $extra = NULL)
    [...] ORM::factory('role', array('name' => 'unverified')) [...]

Извините, приятель, вы не можете этого сделать, поскольку нет (вменяемого) способа макетировать статический вызов метода.

Аргумент, почемуЭта проблема похожа на одно из сообщения в блоге Себастьяна Бергманна: Testing-Code-That-Uses-Singletons

Существуют варианты, такие как runkit, которые можно выбрать для замены "ORM "класс во время выполнения с поддельной версией, но это действительно больно.

Итак, есть несколько вариантов:

Вы можете создать что-то вроде Policy_File_Upload_Data_Provider, котороеимеет метод ->getRoles, в котором вы предоставляете доступ к ORM.Это позволило бы вам хорошо протестировать свою бизнес-логику и протестировать, что класс доступа к данным должен быть немного проще, чем слишком (просто доступ к orm).

Вы можете добавить свой класс ORM (илиесли это не сработает, может быть, просто его имя).В зависимости от самого класса, вы сможете создать экземпляр и вызвать -> factory, как если бы это был обычный метод.Вы можете поиздеваться над этим.

Если вы не хотите, чтобы это просто оставлялось там, это тоже НАСТОЛЬКО плохой вариант.

Надеюсь, что, по крайней мере, вы получили идею / обзор.


Дополнительные ссылки, почему трудно проверить статику:

Misko Hevery - Flaw: Brittle Global State & Singletons

Kore Nordmann - Static considered harmful

...