PHP 단위 테스트를 실행하는 동안 CLI로 출력하는 방법은 무엇입니까?


151

PHPUnit 테스트를 실행할 때 출력을 덤프하여 하나 또는 두 가지를 디버깅 할 수 있기를 원합니다.

나는 다음을 시도했다 ( PHPUnit Manual 예제 와 유사 );

class theTest extends PHPUnit_Framework_TestCase
{
    /**
     * @outputBuffering disabled
     */
    public function testOutput() {
        print_r("Hello World");
        print "Ping";
        echo "Pong";
        $out = "Foo";
        var_dump($out);
    }   
}

결과는 다음과 같습니다.

PHPUnit @package_version@ by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 3.00Mb

OK (1 test, 0 assertions)

예상되는 출력이 없습니다.

2011 년 9 월 19 일 현재 git repos 의 HEAD 버전을 사용하고 있습니다.

출력 php -version:

$ php -version
PHP 5.2.9 (cli) (built: Dec  8 2010 11:36:37) 
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2009 Zend Technologies
    with Xdebug v2.1.0, Copyright (c) 2002-2010, by Derick Rethans

내가 잘못하고있는 것이 있습니까, 아니면 잠재적으로 PHPUnit 버그입니까?


1
testOutput()메소드 를 호출하는 코드는 어디에 있습니까 ?
데릭 터커

실제로 필사적으로 시도 (에코, 인쇄, print_r, var_dump-기본적으로 모든 "출력"), 일반적으로 테스트에서 출력하는 데 문제가 없습니다. 출력 버퍼링이 활성화되어 있는지 확인할 수 있습니다 : php.net/manual/en/function.ob-get-level.php- 그리고 강제로 "테스트"하는 가장 안전한 방법은 예외 BTW를 발생시키는 것입니다.
hakre

3
@DerrickTucker PHPUnit은 phpunit /path/to/tests/theTest.php(위의 클래스가 파일에 있다면) 호출 하여이를 수행합니다 theTest.php.
Jess Telford

@hakre는를 ob_get_level()반환합니다 1. 그러나 이것은 다음 코드 while (ob_get_level() > 0) { ob_end_flush(); }와 모순됩니다 ob_end_clean(): failed to delete buffer. No buffer to delete.. 호기심과 호기심.
Jess Telford

1
그것은 phpunits의 코드가 오류를 일으킨다는 것을 말하고 있습니다. 분명히 phpunits 출력 삼키기가 활성화되어 있기 때문입니다 (그러나 파산했습니다). 정확하게 보면 함수 이름도 다릅니다.
hakre

답변:


196

최신 정보

--verbose커맨드 라인 옵션 보다 훨씬 잘 작동하는 다른 방법을 깨달았습니다 .

class TestSomething extends PHPUnit_Framework_TestCase {
    function testSomething() {
        $myDebugVar = array(1, 2, 3);
        fwrite(STDERR, print_r($myDebugVar, TRUE));
    }
}

이를 통해 --verboseCLI 옵션 과 함께 제공되는 원치 않는 모든 출력없이 언제든지 콘솔에 무엇이든 덤프 할 수 있습니다 .


다른 답변에서 언급했듯이 다음과 같은 내장 방법을 사용하여 출력을 테스트하는 것이 가장 좋습니다.

$this->expectOutputString('foo');

그러나 때로는 테스트 케이스 내에서 장난 꾸러기 일회성 / 일시적 디버깅 결과를 보는 것이 도움이됩니다. var_dump그러나 해킹 / 해결 방법이 필요하지 않습니다 . --verbose테스트 스위트를 실행할 때 명령 행 옵션 을 설정하면 쉽게 수행 할 수 있습니다 . 예를 들면 다음과 같습니다.

$ phpunit --verbose -c phpunit.xml

CLI 환경에서 실행할 때 테스트 메소드 내부의 출력이 표시됩니다.

PHPUnit 테스트 테스트 출력 작성을 참조하십시오 .


5
죄송합니다, stderr에 편지를 쓰지 못했습니다. 실제로 작동합니다. fwritefile_put_contents('php://stderr', $myDebugVar, FILE_APPEND); 메시지 Use of undefined constant STDERR - assumed 'STDERR'가 있었기 때문에 대신 대신 사용해야 했습니다 .
08:07에

문제는 이것이 프로세스 격리와 함께 작동하지 않는 것입니다.
donquixote

@donquixote STDERR 스트림 출력이 폐기 될 가능성이있는 다른 프로세스에서 테스트가 실행되므로 놀랍지 않습니다.
rdlowrey

1
STDOUT대신 사용할 수도 있습니다STERR
Chris

2
예. 작동하고와 같은 방식으로 출력하는 것 같습니다 STDERR. PHPUnit 4.5.0Windows cmd 줄에서 사용 하고 있습니다. echo문은 동일한 결과를 제공하지 않습니다. echo테스트 결과가 표시된 후에 만 ​​출력됩니다. fwrite(STDERR, 'string')또는 fwrite(STDOUT,'string')동일한 결과를 생성합니다. 테스트 결과 이전의 출력이 표시됩니다.
Chris

33

업데이트 : 훨씬 간단한 해결 방법으로 사용하는 방법에 대해서는 아래 rdlowrey의 업데이트를 참조하십시오fwrite(STDERR, print_r($myDebugVar, TRUE));


이 행동은 의도적입니다 ( jasonbar지적했듯이 ). 매뉴얼의 충돌 상태 가 PHPUnit 에보고 되었습니다 .

해결 방법은 PHPUnit이 예상 출력이 비어 있는지 (사실 출력이있을 때) 비어 있다고 가정하여 예기치 않은 출력이 표시되도록하는 것입니다.

class theTest extends PHPUnit_Framework_TestCase
{
    /**
     * @outputBuffering disabled
     */
    public function testOutput() {
        $this->expectOutputString(''); // tell PHPUnit to expect '' as output
        print_r("Hello World");
        print "Ping";
        echo "Pong";
        $out = "Foo";
        var_dump($out);
    }   
}

제공합니다 :

PHPUnit @package_version@ by Sebastian Bergmann.

F

Time: 1 second, Memory: 3.50Mb

There was 1 failure:

1) theTest::testOutput
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-''
+'Hello WorldPingPongstring(4) "Foo"
+'

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

출력 어설 션을 테스트하기 전에 테스트에 실패한 다른 어설 션을 비활성화해야합니다 (따라서 출력이 표시되지 않음).


33

사용해보십시오 --debug

포함 또는 소스 데이터 파일의 올바른 경로를 얻으려고 할 때 유용합니다.


2
이것은 나에게 정답입니다. 이전 답변으로 작성된 모든 fwrite 문은 효과가 없었습니다.
Kim Stacks

9

버그는 아니지만 의도적입니다. 가장 좋은 방법은 어떤 종류의 로그 파일에 쓰고 로그를 출력하여 출력을 감시하는 것입니다.

출력을 테스트하려는 경우 이를 확인 하십시오 .

또한:

참고 : PHPUnit은 테스트 실행 중 발생하는 모든 출력을 삼킨다는 점에 유의하십시오. 엄격 모드에서는 출력을 방출하는 테스트가 실패합니다.


1
의도적 이었다면, 매뉴얼은 반드시 그 예를 제시 하지 않았을 입니까? 또한 출력 자체를 테스트하지 않습니다. 그것을 사용하지 말아야 할 때 테스트를 실패시키는 몇 가지 결과를 안구에 사용합니다.
Jess Telford

서면으로 : 나는 일반적으로 테스트가 실행될 때 반향하는 데 문제가 없습니다. 입력을 잡는 구성이있을 수 있습니다.
hakre

1
의도적이지 않다면 반드시 매뉴얼에이라고 말하지 않았을 것입니다 .
jasonbar

1
따라서 문서에서 충돌이있는 것 같습니다. @hakre는 내가 삼키지 말아야했던 것과 같은 인상을 받고있는 것으로 보입니다. 문서의 어느 부분이 맞습니까?
Jess Telford

--disallow-test-output (또는 conf 파일에 beStrictAboutOutputDuringTests = "true")이있는 경우에만 출력 생성 테스트가 실패합니다. 이제 문서에 "예를 들어 테스트 코드 또는 테스트 된 코드에서 인쇄를 호출하여 출력을 내보내는 테스트, 이 확인을 사용하면 위험으로 표시됩니다. " phpunit.readthedocs.io/en/8.4/risky-tests.html#risky-tests
NULL 포인터

7

VisualPHPUnit 과 함께 운이 좋으며 무엇보다도 출력을 유용하게 보여줍니다.

class TestHello extends PHPUnit_Framework_TestCase 
{
    public function test_Hello() 
    {
        print "hello world";
    }
}

TestHello 결과


흠, 왜 downvote? PHPUnit 테스트에서 디버그 출력을 덤프하는 대체 방법으로 도움이되지 않습니까?
Bob Stein

1
추측 사람의 시도는이를 실행하는 경우 구문 오류가 발생합니다 때문에이을 downvoted됩니다. 거대한 것.
Jimbo

D' oh 나는 기능을 잊었다. 이제 수정, 테스트, 잘라 내기 및 붙여 넣기가 완료되었습니다. 감사합니다, @Jimbo
Bob Stein

안타깝게도 현재 PHP 7과 호환되지 않습니다. "VisualPHPUnit은 현재 PHP PHP와 호환되지 않습니다. phpunit 사용 방식으로 인해 PHP 7과 호환되지 않습니다. Php 7은 다음 주요 릴리스에서 지원 될 것입니다"
leo

6

의도를 생각해야합니다. 테스트를 수정하기 위해 디버깅 할 때 정보가 필요하면 테스트가 중단 될 때 다음 주에 다시 정보가 필요합니다.

이것은 테스트가 실패 할 때 항상 정보가 필요하다는 것을 의미합니다 var_dump. 원인을 찾기 위해를 추가하는 것은 너무 많은 작업입니다. 오히려 데이터를 어설 션에 넣습니다.

코드가 너무 복잡하면 사용자 지정 메시지가있는 하나의 어설 션이 코드의 위치, 이유 및 방법을 알 수있는 수준을 알 수있는 수준에 도달 할 때까지 코드를 분할하십시오.


1
당신이 말한 모든 것에 100 % 동의합니다. PHPUnit을 사용하여 궁극적으로 Google의 XML API 중 하나를 호출하는 통합 테스트를 수행하고 있습니다. 모든 단위 테스트는 통과했지만 (API 호출을 모의) 최종 테스트 (실시간 API 호출)는 실패했습니다. 그것이 Google API의 결함 이라는 것이 밝혀 졌지만 그 동안 원시 HTTP 응답을 덤프하고 싶었습니다.
Jess Telford

2
여기에 설명 된 내용을 달성하기 위해 코드를 디버깅해야하는 경우 어떻게해야합니까?
David Meister 16:24에

2
그렇기 때문에 사용자가 원하는 것을 추측하는 답변이 마음에 들지 않습니다. 캐시 지우기를 기다리는 테스트를했기 때문에 여기에 있습니다. 5 초 캐시 ttl을 사용하면 테스트 ~ 16 초 동안 중단 되는 것처럼 보입니다 . 나는 단지 아무 것도 잘못하지 않고 캐시가 시간 초과되기를 기다리는 중이라는 것을 사용자에게 알리고 싶습니다. 사람들이 그 질문에 대답 할 수 있다면, 다른 유스 케이스를 가진 사람들도 답변을 얻을 수 있습니다.
user151841

4

laravel 5에서는 dump ()를 사용할 수 있으며 마지막 응답에서 내용을 덤프합니다.

class ExampleTest extends TestCase{
    public function test1()
    {
        $this->post('/user', ['name' => 'Gema']);
        $this->dump();
    }
}

준다


4

phpunit을 실행할 때 --verbose 플래그를 사용하십시오 .

$ phpunit --verbose -c phpunit.xml 

이 방법의 장점은 테스트 코드를 변경할 필요가없고, 원하는 문자열, var_dump를 인쇄 할 수 있으며, 상세 모드가 설정된 경우에만 콘솔에 표시된다는 것 입니다.

이게 도움이 되길 바란다.


3

어떤 경우에는 콘솔에 무언가를 출력하기 위해 그런 것을 사용할 수 있습니다

class yourTests extends PHPUnit_Framework_TestCase
{
    /* Add Warnings */
    protected function addWarning($msg, Exception $previous = null)
    {
        $add_warning = $this->getTestResultObject();
        $msg = new PHPUnit_Framework_Warning($msg, 0, $previous);
        $add_warning->addWarning($this, $msg, time());
        $this->setTestResultObject($add_warning);
    }

    /* Add errors */
    protected function addError($msg, Exception $previous = null)
    {
        $add_error = $this->getTestResultObject();
        $msg = new PHPUnit_Framework_AssertionFailedError($msg, 0, $previous);
        $add_error->addError($this, $msg, time());
        $this->setTestResultObject($add_error);
    }

    /* Add failures */
    protected function addFailure($msg, Exception $previous = null)
    {
        $add_failure = $this->getTestResultObject();
        $msg = new PHPUnit_Framework_AssertionFailedError($msg, 0, $previous);
        $add_failure->addFailure($this, $msg, time());
        $this->setTestResultObject($add_failure);
    }

    public function test_messages()
    {
        $this->addWarning("Your warning message!");
        $this->addError("Your error message!");
        $this->addFailure("Your Failure message");
    }

    /* Or just mark test states! */
    public function test_testMarking()
    {
        $this->markTestIncomplete();
        $this->markTestSkipped();
    }
}

3

Hackish, 작동 : 디버그 출력을 메시지로하여 예외를 발생시킵니다.

class theTest extends PHPUnit_Framework_TestCase
{
    public function testOutput() {
        throw new \Exception("hello");
    }   
}

수율 :

...
There was 1 error:

1) theTest::testOutput
Exception: hello

2

이것은 Fixtures에 대한 PHPUnit Docs 에서 가져온 것입니다 .

이를 통해 phpunit 테스트 수명주기 동안 언제든지 정보를 덤프 할 수 있습니다.

__METHOD__아래 코드에서 원하는 출력으로 바꾸십시오 .

예 4.2 : 사용 가능한 모든 템플릿 방법을 보여주는 예

<?php
class TemplateMethodsTest extends PHPUnit_Framework_TestCase
{
    public static function setUpBeforeClass()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
    }

    protected function setUp()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
    }

    protected function assertPreConditions()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
    }

    public function testOne()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
        $this->assertTrue(TRUE);
    }

    public function testTwo()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
        $this->assertTrue(FALSE);
    }

    protected function assertPostConditions()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
    }

    protected function tearDown()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
    }

    public static function tearDownAfterClass()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
    }

    protected function onNotSuccessfulTest(Exception $e)
    {
        fwrite(STDOUT, __METHOD__ . "\n");
        throw $e;
    }
}
?>

1

Testresults HTML을 기반으로 출력했습니다.이 경우 내용을 플러시하는 것이 도움이되었습니다.

var_dump($array);
ob_flush();

두 번째 PHP 메소드가 있습니다

flush() 

내가 시도하지 않은.


1

PHPUnit이로 출력을 숨기고 ob_start()있습니다. 일시적으로 비활성화 할 수 있습니다.

    public function log($something = null)
    {
        ob_end_clean();
        var_dump($something);
        ob_start();
    }

0

이 코드가 작동하려면 소스 코드수정 해야 했으므로이 포크 리포지토리의 URL 을 작곡가에 추가해야 작동합니다.

class TestCase extends \PHPUnit_Framework_TestCase
{
    /**
     *  Save last response
     * @var Response|null A Response instance
     */
    static $lastResponse;
    /**
     *  Modify to save response
     *
     * @param  string $method
     * @param  string $uri
     * @param  array $parameters
     * @param  array $files
     * @param  array $server
     * @param  string $content
     * @param  bool $changeHistory
     * @return \Illuminate\Http\Response
     */
    final public function call(
        $method,
        $uri,
        $parameters = [],
        $files = [],
        $server = [],
        $content = null,
        $changeHistory = true
    ) {

        $response = parent::call($method, $uri, $parameters, $files, $server, $content, $changeHistory);
        static::$lastResponse = $this->client->getResponse();
        return $response;
    }


    /**
     * Modify message to add response text
     *
     * @param mixed $value
     * @param PHPUnit_Framework_Constraint $constraint
     * @param string $message
     * @since  Method available since Release 3.0.0
     */
    final public static function assertThat($value, PHPUnit_Framework_Constraint $constraint, $message = '')
    {
        $message .= PHP_EOL . static::$lastResponse . PHP_EOL;
        parent::assertThat($value, $constraint, $message);
    }
}

0

다음은 PHPUnit 4.x에서 디버그 메시지를 인쇄하는 데 유용한 몇 가지 방법입니다.

  • syslog(LOG_DEBUG, "Debug: Message 1!");

    더 실용적인 예 :

    syslog(LOG_DEBUG, sprintf("%s: Value: %s", __METHOD__, var_export($_GET, TRUE)));

    호출 syslog()하면 시스템 로그 메시지가 생성됩니다 (참조 man syslog.conf).

    참고 : 가능한 수준 : LOG_DEBUG, LOG_INFO, LOG_NOTICE, LOG_WARNING, LOG_ERR, 등

    macOS에서 syslog 메시지를 실시간으로 스트리밍하려면 다음을 실행하십시오.

    log stream --level debug --predicate 'processImagePath contains "php"'
  • fwrite(STDERR, "LOG: Message 2!\n");

    참고 : stdinSTDERR 에서 PHP 스크립트를 읽는 경우 상수를 사용할 수 없습니다 . 해결 방법 은 다음과 같습니다 .

    참고 : 대신 STDERR파일 이름을 지정할 수도 있습니다.

  • file_put_contents('php://stderr', "LOG: Message 3!\n", FILE_APPEND);

    참고 : STDERR상수를 정의 하지 않은 경우이 방법을 사용하십시오 .

  • register_shutdown_function('file_put_contents', 'php://stderr', "LOG: Message 4!\n", FILE_APPEND);

    참고 : 테스트에 영향을주지 않고 맨 끝에 무언가를 인쇄하려면이 방법을 사용하십시오.

변수를 덤프하려면 var_export()예 를 들어을 사용하십시오 "Value: " . var_export($some_var, TRUE) . "\n".

상세 또는 디버그 모드에서만 위의 메시지를 인쇄하려면 다음을 참조하십시오. 테스트에서 --debug 또는 --verbose가 PHPUnit에 전달되었는지 확인하는 방법이 있습니까?


출력 테스트가 자체 테스트의 일부인 경우 출력 문서 테스트 페이지를 확인 하십시오.


-1

Laravel을 사용하는 경우 info ()와 같은 로깅 기능을 사용하여 스토리지 / 로그에서 Laravel 로그 파일에 로깅 할 수 있습니다. 따라서 터미널이 아니라 로그 파일에 나타납니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.