Hướng dẫn phpunit expectexceptionmessage - phpunit mong đợiexceptionmessage

Bạn không thể kiểm tra chi nhánh đó khi mã đứng.

Khối thử thử của bạn không thực sự bắt được bất kỳ ngoại lệ nào. (date ném một lỗi không bị bắt. Vì vậy, nếu bạn có thể tái cấu trúc nó và vượt qua thời gian không được liệt kê là hợp lệ, bạn có thể có được ngoại lệ (điều mà bạn nên có vẻ như đó là ý định của bạn để bắt các trường hợp ngoại lệ ở đây).

function convert_timezone($dt, $tzFrom, $tzTo, $format) {
    $newDate = '';

    $tzFromFull = timezone_name_from_abbr($tzFrom);
    $tzToFull = timezone_name_from_abbr($tzTo);

    if( $tzFromFull != $tzToFull ) {
        try {
            $dtFrom = new DateTimeZone($tzFromFull);
            $dtTo = new DateTimeZone($tzToFull);


            // find the offsets from GMT for the 2 timezones
            $current = new DateTime(date('c',$dt));
            $offset1 = $dtFrom->getOffset($current);
            $offset2 = $dtTo->getOffset($current);
            $offset = $offset2 - $offset1;

            // apply the offset difference to the current time
            $newDate = date($format, $current->format('U') + $offset);
        } catch (Exception $e) {
            $newDate = date($format.' (T)', $dt);
        }
    } else {
        $newDate = date($format, $dt);
    }

    return $newDate;
}

Sau đó, bài kiểm tra sẽ là

function test_convert_timezone() {
   $dt = mktime(0,0,0,1,1,2000);
   $tzFrom = 'foo';
   $tzTo = 'EDT';
   $format = 'd/m/Y g:i a';
   $result = convert_timezone($dt, $tzFrom, $tzTo, $format);
   $this->assertEquals($result, '01/01/2000 1:00 am');
}

Trong thử nghiệm này,

function test_convert_timezone() {
   $dt = mktime(0,0,0,1,1,2000);
   $tzFrom = 'foo';
   $tzTo = 'EDT';
   $format = 'd/m/Y g:i a';
   $result = convert_timezone($dt, $tzFrom, $tzTo, $format);
   $this->assertEquals($result, '01/01/2000 1:00 am');
}
1 sẽ trả về
function test_convert_timezone() {
   $dt = mktime(0,0,0,1,1,2000);
   $tzFrom = 'foo';
   $tzTo = 'EDT';
   $format = 'd/m/Y g:i a';
   $result = convert_timezone($dt, $tzFrom, $tzTo, $format);
   $this->assertEquals($result, '01/01/2000 1:00 am');
}
2, điều này sẽ khiến hàm tạo
function test_convert_timezone() {
   $dt = mktime(0,0,0,1,1,2000);
   $tzFrom = 'foo';
   $tzTo = 'EDT';
   $format = 'd/m/Y g:i a';
   $result = convert_timezone($dt, $tzFrom, $tzTo, $format);
   $this->assertEquals($result, '01/01/2000 1:00 am');
}
3 ném một ngoại lệ đến chi nhánh của bạn.

IMO, bạn muốn tránh xây dựng các đối tượng mà bạn sẽ sử dụng trong các chức năng của mình. Đối với mã này, tôi sẽ vượt qua hai đối tượng Datetimezone cũng như đối tượng DateTime và thực hiện các hoạt động trên chúng. Di chuyển việc tạo ra các đối tượng khác này thành một chức năng/lớp khác. Bằng cách này, bạn có thể chế giễu các đối tượng DateTimezone và DateTime và có nhiều quyền kiểm soát hơn những gì đang xảy ra. Mã này không quá tệ nhưng nó có thể gây rắc rối với việc cố gắng kiểm tra những thứ khác.

Ngoài ra, hãy cẩn thận về việc bắt một ngoại lệ chung trong mã của bạn. Nếu bạn đang sử dụng một đối tượng giả trong một khối thử, mã của bạn có thể bắt được một lỗi không thành công (ném khi một giả không được gọi với các tham số phù hợp hoặc tương tự) sẽ bị bắt bởi mã của bạn. Làm cho nó trông giống như bài kiểm tra của bạn đang trôi qua khi nó thực sự không. Một lần nữa không phải là vấn đề ở đây do mã và thiếu giả nhưng tôi muốn làm cho bạn nhận thức được nó.

Php 7.4 và Phpunit 9

Sử dụng ví dụ về trang chủ PHPUNIT (https://phpunit.de/getting-started/phpunit-9.html):

private function ensureIsValidEmail(string $email): void
{
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        throw new InvalidArgumentException(
            sprintf(
                '"%s" is not a valid email address',
                $email
            )
        );
    }
}

Trang chủ cũng chỉ cho chúng tôi cách kiểm tra ngoại lệ được ném bằng phương pháp

function test_convert_timezone() {
   $dt = mktime(0,0,0,1,1,2000);
   $tzFrom = 'foo';
   $tzTo = 'EDT';
   $format = 'd/m/Y g:i a';
   $result = convert_timezone($dt, $tzFrom, $tzTo, $format);
   $this->assertEquals($result, '01/01/2000 1:00 am');
}
4:

public function testCannotBeCreatedFromInvalidEmailAddress(): void
{
    $this->expectException(InvalidArgumentException::class);

    Email::fromString('invalid');
}

Thật tuyệt. Nhưng điều gì sẽ xảy ra nếu tôi muốn kiểm tra ngoại lệ không được đưa ra cho đầu vào hợp lệ?not thrown given valid input ?

Nhìn vào các tài liệu (https://phpunit.readthedocs.io/en/9.3/writing-tests-for-phpunit.html#testing-exceptions) Dường như không đề cập đến phương pháp nghịch đảo với

function test_convert_timezone() {
   $dt = mktime(0,0,0,1,1,2000);
   $tzFrom = 'foo';
   $tzTo = 'EDT';
   $format = 'd/m/Y g:i a';
   $result = convert_timezone($dt, $tzFrom, $tzTo, $format);
   $this->assertEquals($result, '01/01/2000 1:00 am');
}
4?

Tôi nên tiếp cận điều này như thế nào?

Chỉnh sửa để thêm:

Chỉ cần làm cho nó hoàn toàn rõ ràng, tôi đang tìm cách kiểm tra một kịch bản

function test_convert_timezone() {
   $dt = mktime(0,0,0,1,1,2000);
   $tzFrom = 'foo';
   $tzTo = 'EDT';
   $format = 'd/m/Y g:i a';
   $result = convert_timezone($dt, $tzFrom, $tzTo, $format);
   $this->assertEquals($result, '01/01/2000 1:00 am');
}
6, tức là ngoại lệ không bị ném.not thrown.

Đã hỏi ngày 1 tháng 9 năm 2020 lúc 20:35Sep 1, 2020 at 20:35

Mã số ít mã hóaLittle Code

1.2352 huy hiệu vàng13 Huy hiệu bạc34 Huy hiệu đồng2 gold badges13 silver badges34 bronze badges

1

Nếu một ngoại lệ chưa từng thấy hoặc bất ngờ được ném, bài kiểm tra sẽ thất bại. Bạn không cần phải làm bất cứ điều gì đặc biệt, chỉ cần chạy mã đang được kiểm tra. Nếu không có xác nhận nào khác trong phương pháp kiểm tra, bạn cũng sẽ phải thực hiện

function test_convert_timezone() {
   $dt = mktime(0,0,0,1,1,2000);
   $tzFrom = 'foo';
   $tzTo = 'EDT';
   $format = 'd/m/Y g:i a';
   $result = convert_timezone($dt, $tzFrom, $tzTo, $format);
   $this->assertEquals($result, '01/01/2000 1:00 am');
}
7 hoặc bạn sẽ nhận được cảnh báo rằng bài kiểm tra không thực hiện bất kỳ xác nhận nào.

public function testCannotBeCreatedFromInvalidEmailAddress(): void
{
    $this->expectNotToPerformAssertions();
    Email::fromString('invalid'); // If this throws an exception, the test will fail.
}

Đã trả lời ngày 1 tháng 9 năm 2020 lúc 20:39Sep 1, 2020 at 20:39

Alex Howanskyalex HowanskyAlex Howansky

47.6K8 Huy hiệu vàng74 Huy hiệu bạc95 Huy hiệu Đồng8 gold badges74 silver badges95 bronze badges

2

Không phải là câu trả lời bạn đang tìm kiếm? Duyệt các câu hỏi khác được gắn thẻ phpunit hoặc đặt câu hỏi của riêng bạn.

Tôi đã tái cấu trúc một cơ sở mã PHP cũ và bao gồm viết các bài kiểm tra mới. Trong khi làm điều đó, tôi đã tìm thấy một phương thức lớp chỉ chấp nhận một tập hợp các giá trị được xác định trước và từ chối bất kỳ giá trị nào khác bằng cách ném một ngoại lệ. Dưới đây là một đại diện đơn giản hóa của lớp này:

<?php

class MyClass
{
    protected $value;

    public function setValue($value)
    {
        if (in_array($value, ['foo', 'bar'])) {
            $this->value = $value;
            return $this;
        }

        throw new RuntimeException("{$value} is not a valid value.");
    }
}

Ngay lập tức, tôi đã viết một bài kiểm tra để kiểm tra xem phương thức có lọc ra các giá trị đầu vào không hợp lệ không:

<?php

use PHPUnit\Framework\TestCase;

class MyTestCase extends TestCase
{
    protected $instance;

    public function setUp()
    {
        $this->instance = new MyClass();
    }

    public function testSetValueRefusesBadInput()
    {
        $this->expectException(RuntimeException::class);
        $this->instance->setValue('baz');
    }
}

Dễ như ăn bánh.

Nhưng điều gì sẽ xảy ra nếu phương thức không xử lý các giá trị đầu vào hợp lệ một cách chính xác? Vì phương thức chỉ chấp nhận một tập hợp nhỏ các giá trị, chúng tôi có thể kiểm tra tất cả chúng. Tuy nhiên, PHPUNIT 6 không có xác nhận

function test_convert_timezone() {
   $dt = mktime(0,0,0,1,1,2000);
   $tzFrom = 'foo';
   $tzTo = 'EDT';
   $format = 'd/m/Y g:i a';
   $result = convert_timezone($dt, $tzFrom, $tzTo, $format);
   $this->assertEquals($result, '01/01/2000 1:00 am');
}
8, cũng không cho phép kiểm tra mà không cần xác nhận.valid input values correctly? Since the method accepts only a small set of values, we could test all of them. However, PHPUnit 6 doesn’t have a
function test_convert_timezone() {
   $dt = mktime(0,0,0,1,1,2000);
   $tzFrom = 'foo';
   $tzTo = 'EDT';
   $format = 'd/m/Y g:i a';
   $result = convert_timezone($dt, $tzFrom, $tzTo, $format);
   $this->assertEquals($result, '01/01/2000 1:00 am');
}
8 assertion, nor does it allow a test without an assertion.

Chúng ta có thể dễ dàng khắc phục những hạn chế này bằng cách thêm một xác nhận vào cuối thử nghiệm (

function test_convert_timezone() {
   $dt = mktime(0,0,0,1,1,2000);
   $tzFrom = 'foo';
   $tzTo = 'EDT';
   $format = 'd/m/Y g:i a';
   $result = convert_timezone($dt, $tzFrom, $tzTo, $format);
   $this->assertEquals($result, '01/01/2000 1:00 am');
}
9) hoặc bằng cách tăng số lượng xác nhận (
private function ensureIsValidEmail(string $email): void
{
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        throw new InvalidArgumentException(
            sprintf(
                '"%s" is not a valid email address',
                $email
            )
        );
    }
}
0). Nếu việc thực hiện phương thức
private function ensureIsValidEmail(string $email): void
{
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        throw new InvalidArgumentException(
            sprintf(
                '"%s" is not a valid email address',
                $email
            )
        );
    }
}
1 không chính xác, một ngoại lệ sẽ được ném, nếu không, khẳng định sẽ được tính đến và PHPUNIT sẽ không phàn nàn về thử nghiệm.

<?php

use PHPUnit\Framework\TestCase;

class MyTestCase extends TestCase
{
    protected $instance;

    public function setUp()
    {
        $this->instance = new MyClass();
    }

    public function testSomethingWorks()
    {
        $this->instance->setValue('bar');
        $this->addToAssertionCount(1);
    }

    public function testAnotherThingWorks()
    {
        $this->instance->setValue('foo');
        $this->assertTrue(true);
    }
}