Làm thế nào để xuất ra CLI trong khi thực hiện các bài kiểm tra Đơn vị PHP?


151

Khi chạy thử nghiệm PHPUnit, tôi muốn có thể kết xuất đầu ra để tôi có thể gỡ lỗi một hoặc hai điều.

Tôi đã thử cách sau (tương tự ví dụ 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);
    }   
}

Với kết quả như sau:

PHPUnit @package_version@ by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 3.00Mb

OK (1 test, 0 assertions)

Lưu ý rằng không có đầu ra dự kiến.

Tôi đang sử dụng các phiên bản CHÍNH của repo git kể từ ngày 19 tháng 9 năm 2011.

Đầu ra của 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

Có bất cứ điều gì tôi đang làm sai, hoặc đây có khả năng là một lỗi PHPUnit không?


1
Mã gọi testOutput()phương thức ở đâu?
Derrick Tucker

Bạn cố gắng thực sự tuyệt vọng (echo, print, print_r, var_dump - về cơ bản tất cả là "đầu ra"), thông thường tôi không gặp vấn đề gì khi thực hiện đầu ra từ các bài kiểm tra. Bạn có thể kiểm tra xem bộ đệm đầu ra có được bật hay không: php.net/manual/en/feft.ob-get-level.php - Và cách an toàn nhất để "kiểm tra" một cách mạnh mẽ là ném BTW ngoại lệ.
hakre

3
@DerrickTucker PHPUnit thực hiện điều này bằng cách gọi phpunit /path/to/tests/theTest.php(nếu lớp trên có trong tệp theTest.php).
Jess Telford

@hakre ob_get_level()trở về 1. Tuy nhiên, điều này bị mâu thuẫn bởi đoạn mã sau: while (ob_get_level() > 0) { ob_end_flush(); }lỗi nào ob_end_clean(): failed to delete buffer. No buffer to delete.. Tò mò và tò mò hơn.
Jess Telford

1
Có nghĩa là mã của phpunit đang gây ra lỗi - rõ ràng là do nuốt đầu ra của phpunits đang hoạt động (nhưng bạn đã phá vỡ nó). Nhìn chính xác, tên chức năng là khác nhau.
hakre

Câu trả lời:


196

CẬP NHẬT

Chỉ cần nhận ra một cách khác để làm điều này hoạt động tốt hơn nhiều so với --verbosetùy chọn dòng lệnh:

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

Điều này cho phép bạn đổ bất cứ thứ gì vào bàn điều khiển của bạn bất cứ lúc nào mà không cần tất cả đầu ra không mong muốn đi kèm với --verbosetùy chọn CLI.


Như các câu trả lời khác đã lưu ý, tốt nhất là kiểm tra đầu ra bằng các phương thức tích hợp sẵn như:

$this->expectOutputString('foo');

Tuy nhiên, đôi khi thật nghịch ngợm và thấy đầu ra gỡ lỗi một lần / tạm thời từ trong các trường hợp thử nghiệm của bạn. Không cần var_dumphack / giải pháp thay thế. Điều này có thể dễ dàng được thực hiện bằng cách đặt --verbosetùy chọn dòng lệnh khi chạy bộ kiểm tra của bạn. Ví dụ:

$ phpunit --verbose -c phpunit.xml

Điều này sẽ hiển thị đầu ra từ bên trong các phương thức thử nghiệm của bạn khi chạy trong môi trường CLI.

Xem: Kiểm tra viết cho PHPUnit - Kiểm tra đầu ra .


5
xin lỗi, bỏ lỡ chúng tôi viết thư cho stderr. Quả thực hoạt động. Tôi chỉ bị buộc phải sử dụng file_put_contents('php://stderr', $myDebugVar, FILE_APPEND);thay thế, bởi vì tôi đã nhắn tin Use of undefined constant STDERR - assumed 'STDERR'với fwrite .
Serge

Vấn đề là điều này dường như không hoạt động với sự cô lập quá trình.
donquixote

@donquixote Không có gì đáng ngạc nhiên khi thử nghiệm sẽ thực hiện trong một quy trình khác mà đầu ra luồng STDERR có thể bị loại bỏ ...
rdlowrey

1
Bạn cũng có thể sử dụng STDOUTthay vìSTERR
Chris

2
Đúng. Nó hoạt động và dường như đầu ra giống như STDERR. Tôi đang sử dụng PHPUnit 4.5.0trong dòng cmd windows. một echotuyên bố không cho kết quả tương tự. echokhông xuất nhưng chỉ sau khi kết quả kiểm tra được hiển thị. fwrite(STDERR, 'string')hoặc fwrite(STDOUT,'string')tạo ra kết quả tương tự: Một đầu ra trước khi kết quả kiểm tra được hiển thị.
Chris

33

Cập nhật: Xem bản cập nhật của ndlowrey bên dưới về việc sử dụng fwrite(STDERR, print_r($myDebugVar, TRUE));như một công việc đơn giản hơn nhiều


Hành vi này là cố ý (như jasonbar đã chỉ ra ). Trạng thái xung đột của hướng dẫn đã được báo cáo cho PHPUnit.

Một cách giải quyết là để PHPUnit xác nhận đầu ra dự kiến ​​trống (khi không có đầu ra) sẽ kích hoạt đầu ra không mong muốn được hiển thị.

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);
    }   
}

cho:

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.

Hãy chắc chắn để vô hiệu hóa bất kỳ xác nhận nào khác mà bạn có cho bài kiểm tra vì chúng có thể thất bại trước khi xác nhận đầu ra được kiểm tra (và do đó bạn sẽ không thấy đầu ra).


33

Hãy thử sử dụng --debug

Hữu ích nếu bạn đang cố gắng có được đường dẫn đúng đến tệp dữ liệu bao gồm hoặc nguồn.


2
Đây là câu trả lời chính xác cho tôi. Tất cả các câu lệnh fwrite được viết trong các câu trả lời trước đó không phù hợp với tôi.
Kim Stacks

9

Đó không phải là một lỗi, nhưng rất nhiều chủ ý. Đặt cược tốt nhất của bạn là ghi vào một tệp nhật ký của một số loại và theo dõi nhật ký để xem đầu ra.

Nếu bạn đang cố gắng TEST đầu ra, hãy kiểm tra điều này .

Cũng thế:

Lưu ý : Xin lưu ý rằng PHPUnit nuốt tất cả đầu ra được phát ra trong quá trình thực hiện kiểm tra. Trong chế độ nghiêm ngặt, một bài kiểm tra phát ra đầu ra sẽ thất bại.


1
Nếu nó là cố ý, thì chắc chắn hướng dẫn sẽ không đưa ra một ví dụ về nó ? Ngoài ra, không cố gắng để kiểm tra đầu ra chính nó. Chỉ sử dụng nó để nhãn cầu một số kết quả khiến các xét nghiệm thất bại khi họ không nên.
Jess Telford

Như đã viết: Tôi thường không gặp vấn đề gì khi lặp lại khi chạy thử. Bạn có thể có một số cấu hình bắt đầu vào.
hakre

1
Nếu nó không cố ý, thì chắc chắn hướng dẫn sẽ không nói rằng đó là .
jasonbar

1
Vì vậy, nó có vẻ như một cuộc xung đột trong tài liệu. @hakre dường như có cùng ấn tượng với tôi (rằng nó không nên bị nuốt) - phần nào của tài liệu là chính xác?
Jess Telford

Các thử nghiệm tạo đầu ra CHỈ thất bại khi --disallow-test-output (hoặc tệp conf có beStrict AboutOutputDuringTests = "true") - tài liệu hiện nói "Một thử nghiệm phát ra đầu ra, ví dụ bằng cách gọi in trong mã thử nghiệm hoặc mã thử nghiệm, sẽ được đánh dấu là rủi ro khi kiểm tra này được kích hoạt. " phpunit.readthedocs.io/en/8.4/risky-tests.html#risky-tests
trỏ NULL

7

Tôi có một chút may mắn với VisualPHPUnit và nó hiển thị đầu ra một cách hữu ích, trong số những thứ khác.

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

Kết quả TestHello


Hmm, tại sao các downvote? Làm thế nào điều này không hữu ích như một cách khác để kết xuất đầu ra gỡ lỗi trong thử nghiệm PHPUnit?
Bob Stein

1
Tôi đoán điều này bị hạ cấp bởi vì nếu bất cứ ai thử chạy nó, bạn sẽ gặp lỗi cú pháp. Một cái đồ sộ.
Jimbo

Tôi đã quên chức năng này. Bây giờ nó đã được sửa chữa, thử nghiệm, cắt và dán. Cảm ơn, @Jimbo
Bob Stein

Đáng buồn là hiện tại nó không tương thích với PHP 7, rõ ràng: "VisualPHPUnit không tương thích với php 7 tại thời điểm này do cách sử dụng phpunit. Php 7 sẽ được hỗ trợ trong phiên bản chính tiếp theo"
leo

6

Bạn nên thực sự nghĩ về ý định của mình: Nếu bạn cần thông tin ngay bây giờ khi gỡ lỗi để sửa bài kiểm tra, bạn sẽ cần nó vào tuần tới khi các bài kiểm tra bị hỏng.

Đây có nghĩa là bạn sẽ cần những thông tin luôn khi thử nghiệm thất bại - và thêm một var_dumpđể tìm ra nguyên nhân chỉ là quá nhiều công việc. Thay vì đưa dữ liệu vào xác nhận của bạn.

Nếu mã của bạn quá phức tạp, hãy chia nó ra cho đến khi bạn đạt đến một mức mà một xác nhận (với một thông báo tùy chỉnh) cho bạn biết đủ để biết nó bị hỏng ở đâu, tại sao và cách sửa mã.


1
Tôi đồng ý 100% với mọi thứ bạn nói. Tôi đang sử dụng PHPUnit để thực hiện các bài kiểm tra Tích hợp mà cuối cùng gọi là một trong các API XML của Google. Tất cả các thử nghiệm Đơn vị đã vượt qua (với các lệnh gọi API bị chế giễu), nhưng thử nghiệm cuối cùng (với các cuộc gọi API trực tiếp) đã thất bại. Hóa ra đó là lỗi của Google API nhưng trong thời gian đó, tôi muốn loại bỏ phản hồi HTTP thô.
Jess Telford

2
Điều gì xảy ra nếu bạn cần gỡ lỗi mã của mình trên đường để đạt được những gì bạn đã phác thảo ở đây?
David Meister

2
Đây là lý do tại sao tôi không thích câu trả lời mà đoán thứ hai người dùng muốn làm gì. Tôi ở đây bởi vì tôi có bài kiểm tra chờ xóa bộ nhớ cache. Với ttls bộ nhớ cache 5 giây, điều đó có nghĩa là thử nghiệm của tôi dường như bị treo trong khoảng 16 giây. Tôi chỉ muốn đưa ra một số thông báo cho người dùng rằng không, không có gì sai, chúng tôi chỉ chờ đợi bộ nhớ cache hết thời gian. Nếu mọi người chỉ có thể trả lời câu hỏi, thì những người có trường hợp sử dụng khác cũng sẽ có câu trả lời của họ.
dùng151841

4

Trong laravel 5, bạn có thể sử dụng dump (), kết xuất nội dung từ phản hồi cuối cùng.

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

cho


4

Chỉ cần sử dụng cờ --verbose khi thực thi phpunit .

$ phpunit --verbose -c phpunit.xml 

Ưu điểm của phương pháp này là bạn không cần thay đổi mã kiểm tra, bạn có thể in chuỗi, var_dump là bất cứ điều gì bạn muốn luôn luôn và nó sẽ chỉ được hiển thị trong bảng điều khiển khi chế độ dài dòng được đặt.

Tôi hi vọng cái này giúp được.


3

Đối với một số trường hợp, người ta có thể sử dụng một cái gì đó như thế để xuất cái gì đó ra bàn điều khiển

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, nhưng hoạt động: Ném một ngoại lệ với đầu ra gỡ lỗi làm thông điệp của nó.

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

Sản lượng:

...
There was 1 error:

1) theTest::testOutput
Exception: hello

2

Điều này được lấy từ Tài liệu PHPUnit về Lịch thi đấu .

Điều này sẽ cho phép bạn kết xuất thông tin tại bất kỳ thời điểm nào trong vòng đời thử nghiệm phpunit.

Chỉ cần thay thế __METHOD__trong mã dưới đây bằng bất cứ điều gì bạn muốn đầu ra

Ví dụ 4.2: Ví dụ hiển thị tất cả các phương thức mẫu có sẵn

<?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

Tôi xuất ra bản Testresults HTML của mình, trong trường hợp này thật hữu ích khi xóa nội dung:

var_dump($array);
ob_flush();

Có một Phương thức PHP thứ hai

flush() 

mà tôi chưa thử.


1

PHPUnit đang ẩn đầu ra với ob_start(). Chúng ta có thể vô hiệu hóa nó tạm thời.

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

0

Tôi đã phải sửa đổi mã nguồn để này hoạt động vì vậy bạn cần thêm URL cho repos rẽ nhánh này vào trình soạn thảo để nó hoạt động

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

Dưới đây là một số phương pháp hữu ích để in thông báo gỡ lỗi trong PHPUnit 4.x:

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

    Ví dụ thực tế hơn:

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

    Gọi syslog()sẽ tạo một thông báo nhật ký hệ thống (xem man syslog.conf:).

    Lưu ý: mức có thể: LOG_DEBUG, LOG_INFO, LOG_NOTICE, LOG_WARNING, LOG_ERR,, vv

    Trên macOS, để truyền phát các thông báo nhật ký hệ thống trong thời gian thực, hãy chạy:

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

    Lưu ý: STDERRHằng số không khả dụng nếu đọc tập lệnh PHP từ stdin . Đây là cách giải quyết .

    Lưu ý: Thay vì STDERR, bạn cũng có thể chỉ định tên tệp.

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

    Lưu ý: Sử dụng phương pháp này, nếu bạn không xác định được STDERRhằng số .

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

    Lưu ý: Sử dụng phương pháp này, nếu bạn muốn in một cái gì đó ở cuối mà không ảnh hưởng đến các bài kiểm tra.

Để kết xuất biến, sử dụng var_export(), ví dụ "Value: " . var_export($some_var, TRUE) . "\n".

Để chỉ in các thông báo ở trên trong chế độ dài hoặc gỡ lỗi, hãy xem: Có cách nào để biết liệu --debug hoặc --verbose đã được chuyển đến PHPUnit trong một bài kiểm tra không?


Mặc dù nếu kiểm tra đầu ra là một phần của bản thân kiểm tra, hãy xem: Trang kiểm tra tài liệu đầu ra .


-1

Nếu bạn sử dụng Laravel, thì bạn có thể sử dụng các chức năng ghi nhật ký như thông tin () để đăng nhập vào tệp nhật ký của Laravel trong bộ lưu trữ / nhật ký. Vì vậy, nó sẽ không xuất hiện trong thiết bị đầu cuối của bạn nhưng trong tệp nhật ký.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.