I want to test a particular method from my Laravel service class. When I test "a good case" all my assertions are green and everything pass, but I wanted to test an edge case when under some circumstances this method throws exception.
When I prepare my data and arguments to get this exception, indeed it's being thrown but I can't $this->expectException()
.
Service I want to test has 4 dependencies:
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;
}
In my test, within setUp()
I mock them:
$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,
);
As you can see, the service I want to test is not mocked but I simply create new instance of it $this->techMed3dSizeMeService = new TechMed3dSizeMeService
.
The method I want to test is:
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)
);
}
Good case passes:
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, '='));
}
For bad case I provide non-existing Order ID and I expect to get Exception:
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
}
Result:
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#
It looks like the exception is thrown but not picked by PHPUnit? What am I doing wrong? I shouldn't use new
?
just move the $this->expectException(ServiceResourceNotFoundException::class);
to before $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
}