我正在尝试创建一个模拟对象并将其传递给构造函数。我收到错误
Users
✘ GetUser ItShouldThrowAnExceptionIfUserDoesNotExist
┐
├ Failed asserting that exception of type "TypeError" matches expected exception "FooExceptionsUserNotFoundException". Message was: "Argument 2 passed to FooClientsUsers::__construct() must be an instance of FooApiUsersApi, 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
├ .
┴
根据文档,这应该有效。
用户类
class Users
{
public function __construct(?string $secret, UsersApi $usersApi = null)
{
}
用户测试类
use MockeryAdapterPhpunitMockeryTestCase;
class UsersTest extends MockeryTestCase
{
public function testGetUser_ItShouldThrowAnExceptionIfUserDoesNotExist()
{
$this->expectException(UserNotFoundException::class);
$this->expectExceptionMessage("User with id, email, or username foo@bar.com not found");
$usersApi = Mockery::mock('UsersApi');
$usersApi->shouldReceive('get')
->andThrow(new UserNotFoundException("User with id, email, or username foo@bar.com not found"));
$usersClient = new Users(null, $usersApi);
}
啊,我刚刚想通了。我需要使用完整的命名空间。
即
取代
$usersApi = Mockery::mock('UsersApi');
跟
$usersApi = Mockery::mock('FooApiUsersApi');
我通常走这条路:
<?php
namespace TestsUnit;
use AppServicesServiceToBeMocked;
use AppServicesServiceToBeTested;
use AppJobsJobToBeTested;
use Mockery;
use MockeryMockInterface;
use TestsTestCase;
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
}
}