-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Doctrine2 Module: Is flush()
before checking the database so necessary?
#21
Comments
|
Let's consider a functional test case containing following steps: 1) sending a POST request with invalid form data, 2) checking the response for validation errors, 3) checking the database record is unchanged. The test case uses the same Doctrine Entity Manager. After the first step UoW contains a "dirty" entity, and on the third step this state will be written to the database and following check will fail. It doesn't look correctly. |
You are right. That's why it's not intended to work that way. It will work the way you are described if your code is something like this: $entity = new MyEntity($data); // UoW doesn't contains "dirty" entity
$em->persist($data); // now it does
if (isValid($entity)) {
$em->flush(); // writing only valid entity
}
// now test can flush even dirty entity because you put it in UoW But you should not persist invalid entity: $entity = new MyEntity($data); // UoW doesn't contains "dirty" entity
if (isValid($entity)) {
$em->persist($data); // UoW will contains only valid entities
$em->flush(); // writing only valid entity
}
// UoW is empty and nothing will be written even after test's flush Best practice: There shouldn't be such thing as invalid or incomplete entity. You should check data before creating it. There is a great talk from Doctrine 2 maintainer Ocramius about this. So it should be something like this: if (isValid($data)) {
$entity = new MyEntity($data);
$em->persist($data); // UoW will contains only valid entities
$em->flush(); // writing only valid entity
} else {
// error
} If it doesn't help please provide some code example. |
What if the POST request in my example above updates the exising database record? ) |
The real question is "what problem do we solve by flushing before checking the database record?" |
Maybe we should |
@artmnv an example with inconsistent entity is correct. Yet, the situation is somehow nonsense. Lets consider we have a code echo $someEntity->getSomeProperty(); // some property value
$someEntity->setSomeProperty('another property value'); // we've changed state
$this->entityManager->persist($someEntity); // we have staged state
#$this->entityManager->flush(); // ooops, we've forgotten to flush our changes yep, now we have functional test $I->seeInRepository(SomeEntity::class, ['someProperty' => 'another property value']); What do we have here? Testcase that matches wrong assert for in reality we DON'T have SomeEntity with that property value in our database. And this is the trouble. |
I was just about to open a new issue with the title: "Doctrine Module My app code looks like this (as recommended at https://symfony.com/doc/current/forms.html#handling-form-submissions ): if ($form->isSubmitted() and $form->isValid())
{
$em->persist($user);
$em->flush();
} So I'm doing the validation on the form, not on the entity. And I do have a custom callback validator on the entity (see https://symfony.com/doc/current/reference/constraints/Callback.html ). (After reading the post by @artmnv above, I'm not 100% sure anymore that this is the right/best way to do it - but it works ;-) Anyway, as @AntonTyutin and @TemirkhanN are saying: The test produces false results, and this is a serious issue! |
I'm agree this flush seems to be redundant. Even if you don't persist inconsistent entities, it does nothing. But I don't know how it will affect existing tests. Maybe it should be removed in next major release? Btw you can extend Doctrine2 Module and add custom method without flush like this:
|
If you want to remove something in 2.6.0, please do it quickly. |
@Naktibalda I can do PR and tests. But I'm not confident at this decision. What do you think about this issue? |
This issue is more complex than it seams. I'm agree with your false-positive and false-negative examples. And we can remove I think in @ThomasLandauer example where Form module makes your entity invalid before form validation you should explicitly discard invalid entity (or stop using module with such bad design) if ($form->isSubmitted() and $form->isValid()) {
$em->persist($user);
$em->flush();
} else {
$em->refresh($user);
} In the @TemirkhanN example of false-positive test if we remove So this I think we should not remove |
even if developer has such complicated implicit flush that looks and works awful it still works correct for it is the part of an application(even if it is third party like this example). But we are talking about testing framework and it has side effect on application. $someService->doSomeStuff(); // This place changes states of some pool of entities
$anotherService->doAnotherStuff(); // And here developer implicitly calls flush to save previous service actions an example above demonstrates bad practice/architecture yet code works as expected and shall STOP working if we switch those two lines. And here we go again to unexpected actions from testing framework that hides such issues giving same result(for example above) no matter in which order services have been called.
To be honest I don't use codeception anymore and don't really care what happens with this issue. So if nobody else cares than I have nothing against leaving things to be. |
Because of this |
Fix Fatal error: Uncaught Error: Class 'Doctrine\Common\DataFixtures\Purger\ORMPurger' not found in
Why do we flush managed Doctrine entities before checking the database in
Doctrine2::proceedSeeInRepository()
?In functional tests the Entity Manager of application is used in the Codeception Doctrine2 Module. If we do test a request with validation rejection, and we want to be sure the database was not changed, the test result will be false negative (the request fetches and populates some entity, but didn't save changes to the database, and then
dontSeeInRepository()
flushes the invalid entity to the database and does fail).The text was updated successfully, but these errors were encountered: