I'm learning how to write test for my Api Platform based api. I'm using Alice helper RefreshDatabaseTrait
in test class. In documentation it says that this trait wraps every test is transaction and when its done just rolls its back. Because of that when I for example delete Employee using HttpClient and want to assert it was deleted I have to initialize EmpoyeeRepository
again in order for test to pass. If i don't do it 'count()' method returns 10 Employees. Is there a problem with nested transactions or something?
class EmployeeTest extends AbstractTest
{
use RefreshDatabaseTrait;
/** @test
* @group functional
*/
public function deleteEmployee(): void
{
// Arrange
/** @var EmployeeRepository $employeeRepository */
$employeeRepository = static::getContainer()->get(EmployeeRepository::class);
/** @var Employee $employee */
$employee = $employeeRepository->findOneBy([]);
// Act
$this->createClientWithCredentials()
->request('DELETE', '/employees/' . $employee->getUuid());
// Assert
$employeeRepository = static::getContainer()->get(EmployeeRepository::class);
static::assertResponseIsSuccessful();
static::assertEquals(9, $employeeRepository->count([]));
}
}
class AbstractTest extends ApiTestcase
{
private ?string $token = null;
/**
* @throws \JsonException
*/
protected function createClientWithCredentials($token = null): Client
{
$token = $token ?: $this->getToken();
return static::createClient([], ['headers' => ['Authorization' => 'Bearer ' . $token, 'Content-Type' => 'application/json', 'Accept' => 'application/json']]);
}
/**
* Use other credentials if needed.
* @throws \JsonException
*/
protected function getToken($body = []): string
{
if ($this->token) {
return $this->token;
}
$response = static::createClient()->request('POST', '/token', ['json' => $body ?:
[
"email" => "[email protected]",
"password" => "pass"
]
]);
static::assertResponseIsSuccessful();
return json_decode($response->getContent())->token;
}
}
Api Platform 2.6.8, Symfony 6.0, Hautelook/Alice 2.11 Doctrine/orm 2.13.1
CodePudding user response:
you dont state why you reinit the EmployeeRepository
. if you don't then what? you still get the old employee returned?
without knowing further details I will probably assume that it MIGHT be a caching issue.
Repositories or actually more specifically entitymanager keeps a cache that is a bit brittle I have noticed.
Try clearing it
$employeeRepository->getEm()->clear();
where getEm is a custom function that returns the EntityManager
$_em
from the repo.
CodePudding user response:
I've found the problem:
public function deleteEmployee(): void
{
// Arrange
//getContrainer is booting Kernel
/** @var EmployeeRepository $employeeRepository */
$employeeRepository = static::getContainer()->get(EmployeeRepository::class);
/** @var Employee $employee */
$employee = $employeeRepository->findOneBy([]);
// Act
// This method boot's another Kernel!
$this->createClientWithCredentials()
->request('DELETE', '/employees/' . $employee->getUuid());
// Assert
$employeeRepository = static::getContainer()->get(EmployeeRepository::class);
static::assertResponseIsSuccessful();
static::assertEquals(9, $employeeRepository->count([]));
}
So it appears that you cannot boot kernel more than once.