Reputation: 19294
I'm trying to create a mock object and pass it in to a constructor. I'm getting the error
Users
✘ GetUser ItShouldThrowAnExceptionIfUserDoesNotExist
┐
├ Failed asserting that exception of type "TypeError" matches expected exception "Foo\Exceptions\UserNotFoundException". Message was: "Argument 2 passed to Foo\Clients\Users::__construct() must be an instance of Foo\Api\UsersApi, instance of Mockery_0__UsersApi given, called in /Users/tomcaflisch/myproject/tests/Clients/UsersTest.php on line 25" at
├ /Users/tomcaflisch/myproject/lib/Clients/Users.php:26
├ /Users/tomcaflisch/myproject/tests/Clients/UsersTest.php:25
├ .
┴
According to the docs this should work.
Users class
class Users
{
public function __construct(?string $secret, UsersApi $usersApi = null)
{
}
UsersTest class
use Mockery\Adapter\Phpunit\MockeryTestCase;
class UsersTest extends MockeryTestCase
{
public function testGetUser_ItShouldThrowAnExceptionIfUserDoesNotExist()
{
$this->expectException(UserNotFoundException::class);
$this->expectExceptionMessage("User with id, email, or username [email protected] not found");
$usersApi = Mockery::mock('UsersApi');
$usersApi->shouldReceive('get')
->andThrow(new UserNotFoundException("User with id, email, or username [email protected] not found"));
$usersClient = new Users(null, $usersApi);
}
Upvotes: 2
Views: 2388
Reputation: 1853
I usually go this route:
<?php
namespace Tests\Unit;
use App\Services\ServiceToBeMocked;
use App\Services\ServiceToBeTested;
use App\Jobs\JobToBeTested;
use Mockery;
use Mockery\MockInterface;
use Tests\TestCase;
class ServiceToBeTestedTest extends TestCase
{
private ServiceToBeTested $testService;
public function testSomePartThatDoesntUseTheInjectedDependency(): void
{
/** @var ServiceToBeMocked $mockService */
$mockService = Mockery::mock(ServiceToBeMocked::class);
// now you can use it
$this->testService = new ServiceToBeTested($mockService);
// continue with testing
// assert things happened
}
public function testSomePartThatUsesTheInjectedDependency(): void
{
// The part you're testing actually uses the mocked service
// by calling its method mockedMethod, which should in this
// given test return 'a-string-value'
/** @var ServiceToBeMocked $mockService */
$mockService = Mockery::mock(ServiceToBeMocked::class, function (MockInterface $mock) {
$mock->shouldReceive('mockedMethod')
->andReturn('a-string-value');
});
// now you can use it
$this->testService = new ServiceToBeTested($mockService);
// continue with testing
// assert things happened
}
public function testSomethingThatUsesServiceToBeMockedInAJob(): void
{
// In this case we don't need to assign it to a variable
Mockery::mock(ServiceToBeMocked::class, function (MockInterface $mock) {
$mock->shouldReceive('mockedMethod')
->andReturn('a-string-value');
});
// JobToBeTested::handle(ServiceToBeMocked $mockService)
app()->call(JobToBeTested::class . '@handle);
// assert things happened
}
}
Upvotes: 1
Reputation: 19294
Ah I just figured it out. I need to use the full namespace.
i.e.
replace
$usersApi = Mockery::mock('UsersApi');
with
$usersApi = Mockery::mock('Foo\Api\UsersApi');
Upvotes: 3