【发布时间】:2020-04-21 20:25:38
【问题描述】:
我正在尝试让一个简单的“200 响应”测试适用于需要经过身份验证的用户的网站的一部分。我想我已经创建了会话工作,因为在调试期间调用了控制器函数并检索了一个用户(使用$this->getUser())。
但是,随后该函数失败并显示以下消息:
1) App\Tests\Controller\SecretControllerTest::testIndex200Response
expected other status code for 'http://localhost/secret_url/':
error:
Multiple non-persisted new entities were found through the given association graph:
* A new entity was found through the relationship 'App\Entity\User#role' that was not configured to cascade persist operations for entity: ROLE_FOR_USER. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade
persist this association in the mapping for example @ManyToOne(..,cascade={"persist"}).
* A new entity was found through the relationship 'App\Entity\User#secret_property' that was not configured to cascade persist operations for entity: test123. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade pe
rsist this association in the mapping for example @ManyToOne(..,cascade={"persist"}). (500 Internal Server Error)
Failed asserting that 500 matches expected 200.
如果这还没有存储在 (MySQL) 数据库中并使用 Doctrine 检索,这将是有意义的。记录是在每次运行/每次测试时使用夹具创建的。这就是为什么在控制器$this->getUser() 中按预期运行的原因。
我想做的测试:
public function testIndex200Response(): void
{
$client = $this->getAuthenticatedSecretUserClient();
$this->checkPageLoadResponse($client, 'http://localhost/secret_url/');
}
获取用户:
protected function getAuthenticatedSecretUserClient(): HttpKernelBrowser
{
$this->loadFixtures(
[
RoleFixture::class,
SecretUserFixture::class,
]
);
/** @var User $user */
$user = $this->entityManager->getRepository(User::class)->findOneBy(['username' => 'secret_user']);
$client = self::createClient(
[],
[
'PHP_AUTH_USER' => $user->getUsername(),
'PHP_AUTH_PW' => $user->getPlainPassword(),
]
);
$this->createClientSession($user, $client);
return $client;
}
创建会话:
// Based on https://symfony.com/doc/current/testing/http_authentication.html#using-a-faster-authentication-mechanism-only-for-tests
protected function createClientSession(User $user, HttpKernelBrowser $client): void
{
$authenticatedGuardToken = new PostAuthenticationGuardToken($user, 'chain_provider', $user->getRoles());
$tokenStorage = new TokenStorage();
$tokenStorage->setToken($authenticatedGuardToken);
$session = self::$container->get('session');
$session->set('_security_<security_context>', serialize($authenticatedGuardToken));
$session->save();
$cookie = new Cookie($session->getName(), $session->getId());
$client->getCookieJar()->set($cookie);
self::$container->set('security.token_storage', $tokenStorage);
}
这适用于创建客户端、会话和 cookie。
当请求在第一个函数中执行到$url 时,它会进入端点,确认用户确实已通过身份验证。
根据the documentation here,应该通过配置的提供者(在这种情况下使用 Doctrine)“刷新”用户,以检查给定对象是否与存储的对象匹配。
[..] 在下一个请求开始时,它被反序列化,然后传递给您的用户提供程序以“刷新”它(例如,新用户的 Doctrine 查询)。
我希望这也可以确保会话用户被一个 Doctrine 管理的用户对象替换,以防止上述错误。
如何解决会话中的用户在 PhpUnit 测试期间成为托管用户的问题?
(注意:生产代码正常工作,这个问题只在测试期间出现(遗留代码现在开始测试))
【问题讨论】:
标签: symfony doctrine-orm phpunit symfony4