Kiểm tra tiêu đề PHP với PHPUnit


97

Tôi đang cố gắng sử dụng PHPunit để kiểm tra một lớp xuất ra một số tiêu đề tùy chỉnh.

Vấn đề là trên máy của tôi cái này:

<?php

class HeadersTest extends PHPUnit_Framework_TestCase {

    public function testHeaders()
    {
        ob_start();

        header('Location: foo');
        $headers_list = headers_list();
        header_remove();

        ob_clean();

        $this->assertContains('Location: foo', $headers_list);
    }
}

hoặc thậm chí điều này:

<?php

class HeadersTest extends PHPUnit_Framework_TestCase {

    public function testHeaders()
    {
        ob_start();

        header('Location: foo');
        header_remove();

        ob_clean();
    }
}

trả lại lỗi này:

name@host [~/test]# phpunit --verbose HeadersTest.php 
PHPUnit 3.6.10 by Sebastian Bergmann.

E

Time: 0 seconds, Memory: 2.25Mb

There was 1 error:

1) HeadersTest::testHeaders
Cannot modify header information - headers already sent by (output started at /usr/local/lib/php/PHPUnit/Util/Printer.php:173)

/test/HeadersTest.php:9

FAILURES!
Tests: 1, Assertions: 0, Errors: 1.

Điều này trông giống như thể có thứ gì đó khác xuất ra đầu cuối trước khi chạy thử nghiệm mặc dù không có tệp nào khác được bao gồm và không có ký tự nào khác trước phần đầu của thẻ PHP. Nó có thể là một cái gì đó bên trong PHPunit đang gây ra điều này?

Vấn đề có thể là gì?


14
Chỉ muốn đề cập đến điều này nếu có một số người khác quan tâm đến điều này. headers_list () không hoạt động khi chạy PHPunit (sử dụng PHP CLI) nhưng xdebug_get_headers () hoạt động thay thế.
titel

Câu trả lời:


123

Vấn đề là PHPUnit sẽ in tiêu đề ra màn hình và tại thời điểm đó bạn không thể thêm nhiều tiêu đề hơn.

Công việc xung quanh là chạy thử nghiệm trong một quy trình riêng biệt. Đây là một ví dụ

<?php

class FooTest extends PHPUnit_Framework_TestCase
{
    /**
     * @runInSeparateProcess
     */
    public function testBar()
    {
        header('Location : http://foo.com');
    }
}

Điều này sẽ dẫn đến:

$ phpunit FooTest.php
PHPUnit 3.6.10 by Sebastian Bergmann.

.

Time: 1 second, Memory: 9.00Mb

OK (1 test, 0 assertions)

Chìa khóa là chú thích @runInSeparateProcess.

Nếu bạn đang sử dụng PHPUnit ~ 4.1 hoặc thứ gì đó và gặp lỗi:

PHP Fatal error:  Uncaught Error: Class 'PHPUnit_Util_Configuration' not found in -:378
Stack trace:
#0 {main}
  thrown in - on line 378

Fatal error: Uncaught Error: Class 'PHPUnit_Util_Configuration' not found in - on line 378

Error: Class 'PHPUnit_Util_Configuration' not found in - on line 378

Call Stack:
    0.0013     582512   1. {main}() -:0

Hãy thử thêm cái này vào tệp bootstrap của bạn để sửa nó:

<?php
if (!defined('PHPUNIT_COMPOSER_INSTALL')) {
    define('PHPUNIT_COMPOSER_INSTALL', __DIR__ . '/path/to/composer/vendors/dir/autoload.php');
}

7
điều này gây ra những sai sót trong có một số xác định () báo cáo PHPUnit_Framework_Exception: Thông báo: xyz liên tục đã được xác định
Minhaz

1
@mebjas Nghe có vẻ không liên quan.
SamHennessy

4
Tôi nhận được điều này khi đăng ký:PHP Fatal error: Uncaught exception 'Exception' with message 'Serialization of 'SplFileInfo' is not allowed' in phar:///usr/local/bin/phpunit/phpunit/Util/GlobalState.php:211
t1gor

2
Đây chắc chắn là lựa chọn tốt nhất để giải quyết vấn đề. Nó làm việc như một say mê!
xarlymg89

2
Tôi đã phải sử dụng xdebug_get_headers (), để lấy mảng các tiêu đề đã đặt. Hàm toàn cầu headers_list () không hoạt động trong trường hợp của tôi.
Shalom Sam

108

Mặc dù chạy thử nghiệm trong một quy trình riêng biệt không khắc phục được sự cố, nhưng có một chi phí đáng chú ý khi chạy một bộ thử nghiệm lớn.

Cách khắc phục của tôi là hướng đầu ra của phpunit sang stderr, như sau:

phpunit --stderr <options>

Điều đó sẽ khắc phục được sự cố và điều đó cũng có nghĩa là bạn không phải tạo một hàm bao bọc và thay thế tất cả các lần xuất hiện trong mã của mình.


3
Xuất sắc! Không có thay đổi nào đối với mã của tôi, không có quy trình riêng biệt và nó hoạt động.
alexfernandez

nhưng tôi sẽ vẫn thấy các lỗi tôi đã thực hiện và nhận được kết quả của error_reporting (E_ALL) ??
spankmaster79

1
@ spankmaster79 vâng, nó sẽ chuyển sang lỗi tiêu chuẩn của thiết bị đầu cuối của bạn. Theo mặc định, hầu hết các thiết bị đầu cuối sẽ in lỗi chuẩn và lỗi chuẩn cùng nhau, nhưng chúng thực sự là các luồng riêng biệt.
Jon Cairns

tôi đã trở thành được tạo ra !!! tnx đối với thủ thuật này, nó có ý nghĩa, lỗi nên được báo cáo cho người bán hàng !!! Tnx
th3n3rd

42
Bạn có thể thêm stderr="true"phpunit.xml của mình để lưu một vài lần gõ phím.
tszming

9

Như một bên: Đối với tôi headers_list()tiếp tục trả về 0 phần tử. Tôi nhận thấy bình luận của @titel về câu hỏi và nhận thấy nó xứng đáng được đề cập đặc biệt ở đây:

Chỉ muốn đề cập đến điều này nếu có một số người khác quan tâm đến điều này. headers_list()không hoạt động khi chạy PHPunit (sử dụng PHP CLI) nhưng xdebug_get_headers()hoạt động thay thế.

HTH


4

Như đã được đề cập trong một nhận xét, tôi nghĩ rằng đó là một giải pháp tốt hơn để xác định processIsolation trong tệp cấu hình XML như

     <?xml version="1.0" encoding="UTF-8"?>
     <phpunit
        processIsolation            = "true"
        // ... 
     >
     </phpunit>

Như vậy, bạn không cần phải vượt qua tùy chọn --stderr, tùy chọn này có thể khiến đồng nghiệp của bạn khó chịu.


4
Có lẽ tốt hơn nên xác định nó chỉ cho thử nghiệm yêu cầu nó. Đặt nó cho tất cả các bài kiểm tra sẽ chỉ làm cho việc chạy các bài kiểm tra chậm hơn.
Shi

3

Tôi đã có một giải pháp triệt để hơn, để sử dụng $_SESSIONbên trong các tệp đã thử nghiệm / bao gồm của tôi . Tôi đã chỉnh sửa một trong các tệp PHPUnit tại ../PHPUnit/Utils/Printer.php để có "session_start();"trước lệnh "print $ buffer" .

Nó có tác dụng với tôi như một cái duyên. Nhưng tôi nghĩ giải pháp của người dùng "joonty" là tốt nhất cho đến nay.


Bạn đã gửi yêu cầu kéo trong kho lưu trữ chưa? Tôi đoán đây có thể là một vấn đề phổ biến.
t1gor

Cảm ơn đã gợi ý, tôi gọi session_start () trong bootstrap.php phpunit của tôi và nó làm việc cho tôi
bumperbox

0

Một giải pháp thay thế cho @runInSeparateProcess là chỉ định tùy chọn --process-isolate khi chạy PHPUnit:

name@host [~/test]# phpunit --process-isolation HeadersTest.php

Điều đó tương tự để đặt tùy chọn processIsolation = "true" trong phpunit.xml.

Giải pháp này có những ưu điểm / nhược điểm tương tự như việc chỉ định tùy chọn --stderr, tuy nhiên không hoạt động trong trường hợp của tôi. Về cơ bản, không cần thay đổi mã nào, mặc dù có thể có hiệu suất bị ảnh hưởng do chạy mỗi bài kiểm tra trong một quy trình PHP riêng biệt.


Đây có thể là bước đầu tiên để theo dõi nguyên nhân và thực hiện một số thử nghiệm, nhưng để tạo các thử nghiệm có thể bảo trì, chỉ cần nhúng trực tiếp chú thích vào tệp thử nghiệm. Càng ít tùy chọn 'đặc biệt' từ dòng lệnh, việc duy trì cấu hình hệ thống CI càng dễ dàng.
Shi

ai đã từng hạ cấp #fail. câu trả lời này đúng như một lựa chọn khác.
fb

0

Sử dụng tham số --stderr để lấy tiêu đề từ PHPUnit sau các thử nghiệm của bạn.

phpunit --stderr
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.