PHPUnit:我期待异常,它被抛出但“$this->expectException”不起作用
PHPUnit: I expect exception, it's being thrown but "$this->expectException" doesn't work
我想从我的 Laravel 服务 class 中测试一个特定的方法。当我测试“一个好的案例”时,我所有的断言都是绿色的并且一切都通过了,但是我想测试一个边缘案例,在某些情况下这个方法会抛出异常。
当我准备我的数据和参数来获得这个异常时,它确实被抛出但我不能$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
?
只需将 $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
}
我想从我的 Laravel 服务 class 中测试一个特定的方法。当我测试“一个好的案例”时,我所有的断言都是绿色的并且一切都通过了,但是我想测试一个边缘案例,在某些情况下这个方法会抛出异常。
当我准备我的数据和参数来获得这个异常时,它确实被抛出但我不能$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
?
只需将 $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
}