【问题标题】:PHPUnit mocking an object don't workPHPUnit 模拟对象不起作用
【发布时间】:2012-09-26 21:40:27
【问题描述】:

我是 PHPUnit 中模拟对象的新手,无法使其正常工作。我正在构建当前SensioGeneratorBundle(用于 Symfony2)的扩展。我使用通过PEAR 安装的PHPUnit 3.7。它在 PHP 5.3.5 上运行(因为 PEAR 安装在该版本中)。

我的剥离课程是:

ControllerGenerator.php

class ControllerGenerator extends Generator
{
    // ...

    public function generate(BundleInterface $bundle, $controller, array $actions = array())
    {
        // ...
    }
}

GenerateControllerCommand.php

class GenerateControllerCommand extends ContainerAwareCommand
{
    private $generator;

    /**
     * @see Command
     */
    public function configure()
    {
        // ...
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        // ...

        $generator = $this->generator;
        $generator->generate($bundle, $controller);

        // ...
    }

    protected function getGenerator()
    {
        if (null === $this->generator) {
            $this->generator = new ControllerGenerator($this->getContainer()->get('filesystem'), __DIR__.'/../Resources/skeleton/bundle');
        }

        return $this->generator;
    }

    public function setGenerator(ControllerGenerator $generator)
    {
        $this->generator = $generator;
    }
}

GenerateControllerCommandTest.php

class GenerateControllerCommandTest extends GenerateCommandTest
{
    public function testNonInteractiveCommand()
    {
        $bundle = 'FooBarBundle';
        $controller = 'PostController';

        $input = array(
            'command' => 'generate:controller',
            '--bundle' => $bundle,
            '--controller' => $controller,
        );

        $application = $this->getApplication();
        $commandTester = $this->getCommandTester($input);
        $generator = $this->getGenerator();

        $generator
            ->expects($this->once())
            ->method('generate')
            ->with($this->getContainer()->get('kernel')->getBundle($bundle), $controller)
        ;

        $commandTester->execute($input, array('interactive' => false));
    }

    protected function getCommandTester($input = '')
    {
        return new CommandTester($this->getCommand($input));
    }

    protected function getCommand($input = '')
    {
        return $this->getApplication($input)->find('generate:controller');
    }

    protected function getApplication($input = '')
    {
        $application = new Application();

        $command = new GenerateControllerCommand();
        $command->setContainer($this->getContainer());
        $command->setHelperSet($this->getHelperSet($input));
        $command->setGenerator($this->getGenerator());

        $application->add($command);

        return $application;
    }

    protected function getGenerator()
    {
        // get a noop generator
        return $this
            ->getMockBuilder('Sensio\Bundle\GeneratorBundle\Generator\ControllerGenerator')
            ->disableOriginalConstructor()
            ->setMethods(array('generate'))
            ->getMock()
        ;
    }
}

当我运行 PHPUnit 时,我不断收到此错误:

 $ phpunit Tests\Command\GenerateControllerCommandTest

     PHPUnit 3.7.0 by Sebastian Bergmann.

     Configuration read from E:\Wouter\web\wamp\www\wjsnip\vendor\sensio\generator-bundle\Sensio\Bundle\GeneratorBundle\phpunit.xml.dist

     F

     Time: 2 seconds, Memory: 7.25Mb

     There was 1 failure:

     1) Sensio\Bundle\GeneratorBundle\Tests\Command\GenerateControllerCommandTest::testNonInteractiveCommand
     Expectation failed for method name is equal to <string:generate> when invoked 1 time(s).
     Method was expected to be called 1 times, actually called 0 times.

     E:\Wouter\web\wamp\bin\php\php5.3.5\PEAR\phpunit:46

     FAILURES!
     Tests: 1, Assertions: 7, Failures: 1.

为什么会出现此错误?我想我在GenerateControllerCommand::execute 方法中调用了generate 命令?我做错了什么,可能是真的吗?或者这是 PHPunit 中的错误?

【问题讨论】:

    标签: php mocking phpunit symfony-components


    【解决方案1】:

    总之

    您生成两个不同的$generator 对象。通话发生在一个人身上,而另一个人expects 它。


    更长

    您更改了protected function getGenerator() 的行为,但原始函数期望调用该函数会填充$this-&gt;generator

    您的测试无法正常工作,并且该函数期望始终获得相同的生成器,并且您的覆盖函数返回两个不同的对象。

    您将预期调用设置为 1,然后调用发生在对象上。

    只是看着:

        $generator = $this->getGenerator();
    
        $generator
            ->expects($this->once())
            ->method('generate')
            ->with($this->getContainer()->get('kernel')->getBundle($bundle), $controller)
        ;
    
        $commandTester->execute($input, array('interactive' => false));
    }
    

    $generator 变量没有放在任何对象范围内,因此不会对其进行调用,因为每次调用 $this-&gt;getGenerator() 都会生成一个未存储在任何位置的新对象。

    所以在

    protected function getApplication() {
        //...
        $command->setGenerator($this->getGenerator());
        //...
    }
    

    您的对象与测试用例中的对象不同。

    【讨论】:

    • 感谢您的精彩回答!我已经解决了,测试对象的getGeneratorsetGenerator 方法现在与命令对象中的工作方式相同。
    猜你喜欢
    • 2012-08-21
    • 1970-01-01
    • 1970-01-01
    • 2014-03-27
    • 2011-03-09
    • 2019-08-10
    • 1970-01-01
    • 2021-10-31
    • 2012-09-26
    相关资源
    最近更新 更多