symfony + phpunit-如何使用PasswordEncoder依赖项测试UserFactory

问题描述

你好,我的考试有问题。 我正在尝试测试通过UserDto数据创建UserObject的UserFactory。 我不知道如何测试它,因为工厂需要依赖项中的PasswordEncoder。

use App\Entity\User;
use App\Service\Factory\UserFactory;
use PHPUnit\Framework\MockObject\MockObject as MockObject;
use PHPUnit\Framework\TestCase;

class UserFactoryTest extends TestCase
{
    /**
     * @covers UserFactory
     */
    public function testShouldcreateuserObjectFromUserDto()
    {
        //Given
        /**
         * @var UserDto | MockObject
         */
        $userDto = $this->getMockBuilder(UserDto::class);

        //When
        $userFactory = new UserFactory(/* PASSWORD ENCODER */);
        $user = $userFactory->create($userDto);

        //Then
        $this->assertInstanceOf(User::class,$user);
    }
}
namespace App\Service\Factory;

use App\Entity\User;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

class UserFactory
{
    /**
     * @var UserPasswordEncoderInterface
     */
    private $encoder;

    public function __construct(UserPasswordEncoderInterface $encoder)
    {
        $this->encoder = $encoder;
    }

    public function create(UserDto $dto)
    {
        $user = new User();
        $user->setPassword($this->encoder->encodePassword($dto->plainPassword));
        /**
         * CODE..
         */
        return $user;
    }
}

这是对的吗?我如何测试具有依赖性的工厂? 我无法在我的TestClass中使用__construct

解决方法

(提示:显然您使用的是UserPasswordEncoderInterface错误,因为它不是PasswordEncoderInterface-前者还希望将User作为参数,而后者则不是,我今天才学到,您可能想解决这个问题)

通常,您必须为要测试的类提供所有依赖关系。本质上,有不同的方法:实现接口的简化版本(如果是接口),实际找到依赖项并将其实例化,或使用模拟并告诉它将会发生什么。如果您通常知道依赖项会发生什么(非黑盒测试),则可以完成后者。

因此,您可以使用一些定义明确的行为来模拟接口:

//$upe = $this->getMockBuilder(\Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface::class)->getMock();
$upe = $this->getMockBuilder(\Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface::class)->getMock();
$upe->expects($this->any())
            ->method('encodePassword')
            // omit following line,if you don't want to check for param
            ->with($this->equalTo('plainPassword')) 
            ->willReturn('encodedPassword');

,然后将其提供给您的用户工厂:

$userfactory = new UserFactory($upe);

这在某种程度上取决于UserFactory的实现,希望它实际上是以指定的方式调用的,并且始终会返回相同的字符串。 (您可以更深入地模拟和/或自己实现接口以拥有更多控制权)