Pergunta

Eu olhei através das várias perguntas sobre os testes de unidade, mas não consegue encontrar um que responde especificamente a esta questão.

Eu tenho várias classes PHP que contêm funções que olhar como esta:

    static function _setSuspended($Suspended, $UserID)
    {
        try {
            $con = Propel::getConnection();

            $c1 = new Criteria();
            $c1->add(DomainsPeer::USERID,$UserID);

            $update = new Criteria();
            $update->add(DomainsPeer::SUSPENDED,$Suspended);

            BasePeer::doUpdate($c1, $update, $con);

            return true;
        } catch(PropelException $e) {
            return $e->getMessage();
        }
    }

Eu estou usando Propel como meu ORM. Eu li através de vários tópicos de teste de unidade que falar sobre a criação de 'Mocks' e 'Stubs' eo que não, mas eu não tenho sido capaz de encontrar qualquer coisa que especificamente diz-lhe como testar uma função como acima.

Meu pensamento é algo como: eu preciso testar a função acima, então eu gostaria de chamá-lo. Mas se eu chamá-lo, ele usa Propel como o ORM e de acordo com os princípios Teste de Unidade I deve isolar cada função por si só.

Eu só não vejo uma maneira de fazer isso. O que estou ausente aqui?

Foi útil?

Solução

Descobri que zombando da ORM não me dá nenhuma confiança porque a configuração ORM nunca é testado. ORMs também tem muita ação em um efeito de distância, que podem dar uma falsa confiança com testes de unidade. Zombando o driver de banco de dados ou fornecer uma alternativa em memória de banco de dados dá-me muito maior confiança o meu código está correto e é quase tão duro como zombando da ORM.

SQLite é um banco de dados grande na memória para testes de unidade. É na lista de banco de dados PDO suportados. (DOP é o driver de banco de dados Propel 1.3.) Se você não quiser usar um banco de dados in-memory, você pode ser capaz de encontrar um mock DOP já escrita.

Outras dicas

Esta é uma resposta genérica, em que eu não estou familiarizado com Propel em tudo e só um pouco mais familiarizado com PHP. A resposta básica é que você usar injeção de dependência. Em vez de se referir diretamente ao seu ORM, você cria um invólucro em torno dele, então injetar o wrapper em sua classe / função para realmente usar. Para fazer o teste de unidade, em seguida, você criar uma versão falsa ou falsificada do invólucro que não faz interface com o ORM mas em vez disso permite configurar as respostas do wrapper para suas invocações de método. Isso permite que você fator o ORM quando a unidade testar suas funções.

Eu estava tentando resolver o mesmo problema ao construir um PHPUnit plugin para Symfony . Acabei abordá-lo de forma semelhante a do Django teste quadro -. usar um banco de dados / conexão separada, e destruir e reconstruí-lo antes de cada teste

eu descobri que eu também era capaz de fugir com apenas reconstruir o banco de dados de teste antes do primeiro teste em um teste (ou se um teste instrui-lo explicitamente); antes que os outros testes, ele simplesmente apaga todos os dados para acelerar as coisas um pouco.

Estive lendo blog de Misko Hevery sobre o teste muito ultimamente. Ele cobre esta situação; você precisa usar DI (injeção de dependência).

Estou me lutando com isso um pouco também, e eu também uso de propulsão.

Por um lado, você pode mover o método de "suspender" a classe "Objeto" em vez do par. Para esta função particular, de qualquer maneira, você não precisa usar os métodos estáticos para alcançar este objectivo. Sua API poderia ser semelhante a:

MyObjectPeer::retrieveByPK(1)->suspend();

Este seria testável através de métodos normais de teste de unidade.

Se for realmente o banco de dados que precisa ser testado, em seguida, AFAIK você precisa realmente ter o DB envolvida no teste. Eu estou usando ltree e PostGIS muito no meu projeto atual e eu não consigo pensar em qualquer outra maneira de executar testes de unidade para a lógica modelo que depende do DB que não incluí-lo em meus testes.

Este é um exemplo de uma classe com dependência duro que não pode ser unidade testável.

Nós poderíamos ser capazes de teste com uma conexão para outro banco de dados, mas, em seguida, não um teste de unidade é mais, mas um teste de integração.

A melhor alternativa que penso é ter uma classe QueryFactory que irá envolver todos os diferentes métodos que você precisa e, em seguida, você será capaz de zombar-lo.

Em primeiro lugar, em princípio, criar uma interface

interface iQueryFactory
{
    function firstFunction($argument);
    function secondFunction($argument, $argument2);
}

O QueryFactory com todo o seu pedido ORM Precisamos

class QueryFactory implements iQueryFactory
{
    function firstFunction($argument) 
    {
        // ORM thing
    }

    function secondFunction($argument, $argument2)
    {
        // ORM stuff
    }
}

Existe a logique negócios com a injeção da fábrica de consulta

class BusinessLogic 
{
    protected $queryFactory;

    function __construct($queryFactoryInjection) 
    {
        $this->queryFactory= $queryFactoryInjection;
    }

    function yourFunctionInYourBusinessLogique($argument, $argument2) 
    {
        // business logique

        try {
            $this->queryFactory->secondFunction($argument, $argument2);
        } catch (\Exception $e) {
            // log
            // return thing
        }

        // return stuff
    }
}

A parte simulada, nota que eu não uso um quadro de simulação para o meu exemple (btw você pode criar um setter de resposta)

class QueryFactoryMock implements iQueryFactory
{
    function firstFunction($argument) 
    {
        if (is_null($argument)) 
        {
            throw new \Exception("");
        } 
        else 
        {
            return "succes";
        }
    }

    function firstFunction($argument, $argument2) 
    { 
        // sutff  
    }
}

Então, finalmente, a Unidade de Testes que testar a nossa lógica de negócios com a implementação simulada

class BusinessLogicTest extends PHPUnit_Framework_TestCase 
{
    public function setUp() 
    {
        require_once "BusinessLogic.php";
    }

    public function testFirstFunction_WhenInsertGoodName() 
    {
        $queryMockup = new QueryFactoryMock();
        $businessLogicObject = new BusinessLogic($queryMockup);
        $response = $businessLogicObject ->firstFunction("fabien");

        $this->assertEquals($response, "succes");
    }

    public function testFirstFunction_WhenInsetNull() 
    {
        $queryMockup = new QueryFactoryMock();
        $businessLogicObject = new BusinessLogic($queryMockup);
        $response = $businessLogicObject->firstFunction(null);

        $this->assertEquals($response, "fail");
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top