在 php 7.2 的测试中替换 Symfony 服务

Jam*_*May 5 php phpunit symfony php-7.2

我正在尝试将我在 Symfony 3.3 和 php 7.1 上运行的应用程序升级到 php 7.2,但是当我运行 phpunit 时遇到了大量已弃用的消息。最烦人的是:

"user.user_service" 服务已经初始化,替换它自 Symfony 3.3 起已被弃用,并将在 4.0: 7x 中失败

这是因为我在 setUp 方法中有这一行:

$this->userService = $this->getMockBuilder(UserService::class)
    ->setMethods(['update'])
    ->getMock();
$container->set('user.user_service', $this->userService);
Run Code Online (Sandbox Code Playgroud)

7x 是因为我在那个班级有 7 个测试用例,并且为每个测试用例触发了 setUp。我该如何处理这个问题?我无法删除这个模拟,因为它很重要。

我不明白为什么 Symfony 完全指向这个测试用例,因为我在所有测试中都以这种方式替换了很多服务。在这个setUp方法之前我没有在任何地方替换这个服务,所以很奇怪。

Zhu*_*ukV 0

因此,构建容器后,容器是不可变的,您不能向其中添加其他服务/参数(也可以替换,因为这包含两个操作 - 删除和设置)。

但是,在更多情况下,我们应该有机会替换服务内的逻辑。

为此,我仅使用自定义服务进行测试。此服务覆盖默认服务 ( class TestUserService extends UserService) 或使用接口(更好)。创建类后,我在另一个机会中或通过另一个机会声明具有相同名称的服务app/config/test.yml (when@test)

namespace Acme;

interface UserServiceInterface
{
    public function create(object $some): User;
}

/* Original service */
readonly class UserService implements UserServiceInterface
{
    public function create(object $some): User
    {
        // Some actions here
    }
}

/* Service only for test */
class TestUserService implements UserServiceInterface
{ 
    private ?\Closure $callback;
    
    public function shouldExecute(\Closure $callback): void
    {
        $this->callback = $callback;
    }

    public function create(object $some): User
    {
        if ($this->callback) {
            return ($this->callback)($some);
        }
        
        throw new \RuntimeException(\sprintf(
            'The service %s wrong configured. Please call "shouldExecute" method previously.',
            __CLASS__
        ));
    }
}
Run Code Online (Sandbox Code Playgroud)

并在您的配置中声明它(以 YAML 为例):

services:
    user_service:
        class: Acme\UserService

when@test:
    services:
        user_service:
            class: Acme\TestUserService
Run Code Online (Sandbox Code Playgroud)

之后,我可以轻松地将内部的任何逻辑UserService::create仅用于测试环境。

class SomeTest extends TestCase
{
    private TestUserService $userService;
    
    protected function setUp(): void
    {
        $this->userService = self::getContainer()->get('user_service');
    }
    
    public function shouldSuccess(): void
    {
        $this->userService->shouldExecute(static function (object $some) {
            self::assertEquals('foo bar', $some);
            
            return new User();
        });
        
        // logic for testing
    }
}
Run Code Online (Sandbox Code Playgroud)

在少数情况下,开发人员希望有机会仅在特定情况下更改逻辑。为此,我们可以使用装饰器模式,如果未配置回调,则UserService在内部调用 origin 。TestUserService