Pergunta

Para objetos que compõem um outro objeto como parte de sua implementação, qual é a melhor maneira de escrever o teste de unidade tão somente o objeto princípio é testado? Trivial exemplo:

class myObj { 
    public function doSomethingWhichIsLogged()
    {
        // ...
        $logger = new logger('/tmp/log.txt');
        $logger->info('some message');
        // ...
    }
}

Eu sei que o objeto poderia ser projetado de modo que o logger objeto de dependência pode ser injetado e, portanto, ridicularizado em um teste de unidade, mas isso nem sempre é o caso - em cenários mais complicados, você precisa fazer para compor outros objetos ou chamadas make aos métodos estáticos.

Como nós não queremos para testar o objeto logger, apenas o myObj, como é que vamos proceder? Podemos criar uma apagou "double" com o script de teste? Algo como:

class logger
{
    public function __construct($filepath) {}
    public function info($message) {}
}

class TestMyObj extends PHPUnit_Framework_TestCase 
{
    // ...
}

Isto parece viável para pequenos objetos, mas seria uma dor para APIs mais complicado, onde o SUT dependiam os valores de retorno. Além disso, se você quiser testar as chamadas para o objeto de dependência da mesma foi você pode com objetos fictícios? Existe uma maneira de zombar objetos que são instanciado pela SUT em vez de ser aprovada em?

Eu li a página man on simulações mas não parece cobrir esta situação em que a dependência é composta em vez de agregados. Como você faz isso?

Foi útil?

Solução

Como você parece estar ciente já, Betão Classe Dependências faz testes duro (ou completamente impossível). Você precisa dissociar essa dependência. Uma mudança simples, que não quebrar a API existente, é como padrão para o comportamento atual, mas fornecer um gancho para substituí-lo. Há uma série de maneiras que isso poderia ser implementado.

Algumas línguas têm ferramentas que podem injetar aulas simuladas em código, mas eu não sei de nada parecido com isso para PHP. Na maioria dos casos, você provavelmente seria melhor fora de refatorar seu código de qualquer maneira.

Outras dicas

A seguir troelskn aconselhar aqui está um exemplo básico do que você deve fazer.

<?php

class MyObj
{
    /**
     * @var LoggerInterface
     */
    protected $_logger;

    public function doSomethingWhichIsLogged()
    {
        // ...
        $this->getLogger()->info('some message');
        // ...
    }

    public function setLogger(LoggerInterface $logger)
    {
        $this->_logger = $logger;
    }

    public function getLogger()
    {
        return $this->_logger;
    }
}


class MyObjText extends PHPUnit_Framework_TestCase
{
    /**
     * @var MyObj
     */
    protected $_myObj;

    public function setUp()
    {
        $this->_myObj = new MyObj;
    }

    public function testDoSomethingWhichIsLogged()
    {
        $mockedMethods = array('info');
        $mock = $this->getMock('LoggerInterface', $mockedMethods);
        $mock->expects($this->any())
             ->method('info')
             ->will($this->returnValue(null));

        $this->_myObj->setLogger($mock);

        // do your testing
    }
}

Mais informações sobre objetos mock pode ser encontrada no manual .

Parece que eu mal entendido a pergunta, deixe-me tentar novamente:

Você deve usar o padrão singleton ou uma fábrica para a logger, se não é tarde demais já:

class LoggerStub extends Logger {
    public function info() {}
}
Logger::setInstance(new LoggerStub());
...
$logger = Logger::getInstance();

Se você não pode alterar o código, você poderia usar um catch-all classe que está sobrecarregando __ call ()

class GenericStub {
    public function __call($functionName, $arguments) {}
}

Há realmente uma razoavelmente nova extensão para a classe PHP sobrecarga liberado pelos mesmos caras que constroem PHPUnit. Ele permite que você substituir o novo operador nos casos em que você não pode refatorar o código, infelizmente, não é tão simples de instalar no Windows.

A URL é http://github.com/johannes/php -teste-helpers / blob / master /

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top