duandao1931 2018-01-17 09:27
浏览 58
已采纳

在Symfony 3.4中对单元测试中的服务进行模拟

I have a simple DefaultController as service, where the DI is autowired.

class DefaultController extends BaseController
{
    private $logger;
    private $recordRepository;

    public function __construct(LoggerInterface $logger, RecordRepository $recordRepository)
    {
        $this->logger = $logger;
        $this->recordRepository = $recordRepository;
    }

    public function downloadAction($uuid)
    {
        $recordRepo = $this->recordRepository;

        $record = $recordRepo->findActive($uuid);

        $logger = $this->logger;

        if (!$record) {
            $logger->error('Record not found: '.$uuid);

            return $this->render('default/download_error.html.twig', [
                'error' => 'record_not_found'
            ]);
        }
    }
}

I've written a unit test that tries to call this method while also replacing one of the services (the logger) with a mock:

<?php
namespace Tests\AppBundle\Controller;

use Monolog\Logger;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class DefaultControllerTest extends WebTestCase {

    public function testDownloadAction()
    {
        $mock = $this->getMockBuilder(Logger::class)
            ->disableOriginalConstructor()
            ->getMock();

        $mock->expects($this->once())->method('error')
            ->with('Record not found: 1223');

        $client = static::createClient([]);

        $client->getContainer()->set('logger', $mock);

        $client->request('GET', '/download/12233');

        print $client->getResponse()->getContent();

        $this->assertEquals(200, $client->getResponse()->getStatusCode());
    }

}

The problem is, when this test fails (because the logger error and expected string dont match up), the PHPunit message is put in the $client->getResponse output instead of being caught in the CLI.

Output CLI:

PHPUnit 4.8.36 by Sebastian Bergmann and contributors.
F<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <meta name="robots" content="noindex,nofollow" />
        <meta name="viewport" content="width=device-width,initial-scale=1" />
        <title>    Expectation failed for method name is equal to &lt;string:error&gt; when invoked 1 time(s) Parameter 0 for invocation Monolog\Logger::error(&#039;Record not found: 12233&#039;, Array ()) does not match expected value. Failed asserting that two strings are equal. (500 Internal Server Error) </title> 

(further long webpage output removed here)

PHPUnit message:

There was 1 failure:

1) Tests\AppBundle\Controller\DefaultControllerTest::testDownloadAction
Failed asserting that 500 matches expected 200.

Do I have to use a regular PHPUnit case if I want to use mock objects? In that case I should probably refactor the $this->render in the Controller as well.

  • 写回答

1条回答 默认 最新

  • douyan8961 2018-01-17 10:12
    关注

    1) it's no need to write unit tests for controllers. If there is some login, then move it to Manager/Service/AnotherNameForLogicClass and tests it with unit test, but not controller 2) controllers are tested by functional/integrational tests and usually there is no need of mocks in this type of tests.

    There are different articles related to this topic. For example, from KNP: https://knpuniversity.com/screencast/symfony2-ep2/testing

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 mysql架构,按照姓名分表
  • ¥15 MATLAB实现区间[a,b]上的Gauss-Legendre积分
  • ¥15 Macbookpro 连接热点正常上网,连接不了Wi-Fi。
  • ¥15 delphi webbrowser组件网页下拉菜单自动选择问题
  • ¥15 linux驱动,linux应用,多线程
  • ¥20 我要一个分身加定位两个功能的安卓app
  • ¥15 基于FOC驱动器,如何实现卡丁车下坡无阻力的遛坡的效果
  • ¥15 IAR程序莫名变量多重定义
  • ¥15 (标签-UDP|关键词-client)
  • ¥15 关于库卡officelite无法与虚拟机通讯的问题