【问题标题】:PHPUnit: I expect exception, it's being thrown but "$this->expectException" doesn't workPHPUnit:我期待异常,它被抛出但“$this->expectException”不起作用
【发布时间】:2021-03-03 17:46:01
【问题描述】:

我想测试我的 Laravel 服务类中的特定方法。当我测试“一个好案例”时,我所有的断言都是绿色的,一切都通过了,但是我想在某些情况下这个方法抛出异常时测试一个边缘案例。

当我准备我的数据和参数来获取这个异常时,它确实被抛出了,但我不能$this->expectException()

我要测试的服务有 4 个依赖项:

class TechMed3dSizeMeService extends AbstractService implements TechMed3dSizeMeServiceInterface
{
    private DatabaseManager $databaseManager;
    private FileSystem $fileSystem;
    private OrderServiceInterface $orderService;
    private ScanServiceInterface $scanService;

    public function __construct(
        DatabaseManager $databaseManager,
        FileSystem $fileSystem,
        OrderServiceInterface $orderService,
        ScanServiceInterface $scanService
    ) {
        $this->databaseManager = $databaseManager;
        $this->fileSystem = $fileSystem;
        $this->orderService = $orderService;
        $this->scanService = $scanService;
    }

在我的测试中,我在setUp() 内模拟了它们:

        $this->databaseManager = $this->getMockBuilder(DatabaseManager::class)
            ->disableOriginalConstructor()
            ->getMock();

        $this->fileSystem = $this->getMockBuilder(FileSystem::class)
            ->disableOriginalConstructor()
            ->getMock();

        $this->orderService = $this->getMockBuilder(OrderServiceInterface::class)
            ->disableOriginalConstructor()
            ->getMock();

        $this->scanService = $this->getMockBuilder(ScanServiceInterface::class)
            ->disableOriginalConstructor()
            ->getMock();

        $this->techMed3dSizeMeService = new TechMed3dSizeMeService(
            $this->databaseManager,
            $this->fileSystem,
            $this->orderService,
            $this->scanService,
        );

如您所见,我要测试的服务没有被模拟,但我只是创建了它的新实例$this->techMed3dSizeMeService = new TechMed3dSizeMeService

我要测试的方法是:

    public function getUrlScheme(int $orderId): string
    {
        $order = $this->orderService->getOrderById($orderId);

        if (!$order instanceof Order) {
            throw new ServiceResourceNotFoundException(); // I want to get this exception in assertion
        }

        if (!$this->canAccessByOwnershipOrSufficientRole($order)) {
            throw new ServiceAuthorizationException();
        }

        if (!$order->canObtainScansFromExternalApp) {
            throw new OrderNotReadyToObtainScansFromExternalAppException(
                'Requested Order did not pass through required steps to obtain scans.'
            );
        }

        $orderDetails = $order->orderDetailsOrders;

        if (!$orderDetails instanceof OrderDetails) {
            throw new OrderDoesNotHaveOrderDetails(
                'Requested Order does not have Order Details necessary to obtain scans.'
            );
        }

        return sprintf(
            'tm3d-in-3dsizeme://data?params=%s',
            $this->generatePayloadForUrlScheme($order, $orderDetails)
        );
    }

成功案例通过:

    public function get_url_scheme_for_given_order_owned_by_prosthetist()
    {
        // Act as
        $this->actingAs($this->userProsthetist);

        // Create necessary data
        $order = $this->createOrderThanCanObtainScansForUser($this->userProsthetist);
        $this->createOrderDetailsForOrder($order);

        // Invoke
        $this->orderService->expects($this->once())
            ->method('getOrderById')
            ->will($this->returnValue($order));

        // Assert
        $urlScheme = $this->techMed3dSizeMeService->getUrlScheme($order->id);

        $this->assertTrue(Str::startsWith($urlScheme, 'tm3d-in-3dsizeme://data?params='));
        $this->assertTrue(Str::endsWith($urlScheme, '='));
    }

对于不好的情况,我提供了不存在的订单 ID,我希望得到异常:

    public function get_url_scheme_for_given_order_owned_by_prosthetist_where_order_does_not_exist()
    {
        // Act as
        $this->actingAs($this->userProsthetist);

        // Invoke
        $this->orderService->expects($this->once())
            ->method('getOrderById')
            ->will($this->returnValue(null));

        // Assert
        $urlScheme = $this->techMed3dSizeMeService->getUrlScheme(999999); // I provide non existing ID

        $this->expectException(ServiceResourceNotFoundException::class); // I want to get this and I get but this doesn't work
    }

结果:

bash-5.0# ./vendor/bin/phpunit --filter=TechMed3dSizeMeServiceTest
PHPUnit 8.5.13 by Sebastian Bergmann and contributors.

.E                                                                  2 / 2 (100%)

Time: 5.15 seconds, Memory: 28.00 MB

There was 1 error:

1) Tests\Unit\Services\TechMed3dSizeMeService\TechMed3dSizeMeServiceTest::get_url_scheme_for_given_order_owned_by_prosthetist_where_order_does_not_exist
App\Exceptions\Services\ServiceResourceNotFoundException:

/app/app/Services/TechMed3dSizeMeService/TechMed3dSizeMeService.php:45
/app/tests/Unit/Services/TechMed3dSizeMeService/TechMed3dSizeMeServiceTest.php:53

ERRORS!
Tests: 2, Assertions: 3, Errors: 1.
bash-5.0#

看起来异常被抛出但 PHPUnit 没有选择?我究竟做错了什么?我不应该使用new

【问题讨论】:

    标签: php laravel unit-testing laravel-7


    【解决方案1】:

    只需将$this->expectException(ServiceResourceNotFoundException::class); 移动到$urlScheme = $this->techMed3dSizeMeService->getUrlScheme(999999); 之前

    public function get_url_scheme_for_given_order_owned_by_prosthetist_where_order_does_not_exist()
    {
        // Act as
        $this->actingAs($this->userProsthetist);
    
        // Invoke
        $this->orderService->expects($this->once())
            ->method('getOrderById')
            ->will($this->returnValue(null));
    
    
        // Assert
        $this->expectException(ServiceResourceNotFoundException::class);
        $urlScheme = $this->techMed3dSizeMeService->getUrlScheme(999999); // I provide non existing ID
    }
    

    【讨论】:

    • 天啊!你让我的晚上拉斐尔!如此愚蠢的错误,现在它轻而易举!
    猜你喜欢
    • 2011-08-08
    • 2021-04-16
    • 2015-08-29
    • 1970-01-01
    • 2018-03-31
    • 2011-08-06
    • 2017-07-26
    • 2013-09-25
    • 1970-01-01
    相关资源
    最近更新 更多