We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Weird unit tests unexpectedly failing

I am using PHPUnit to test my code. Just to experiment with Phalcon, I have a basic model where I'm setting default values in the initialize method. I have one unit test that ensures these default values are set, and another test to put stuff in the database and test that it's there.

The first test works fine and the second test fails because none of these default values aren't set. If I comment out the first test (which doesn't touch the db) the default values are set and the second test passes. I have no idea why!

My unit test is extending a custom implementation of the incubator's ModelTestCase and in the set up I prepare the DI, set the database and begin a transaction. In the teardown, I rollback the transaction and call the PHPUnit\Framework\TestCase::tearDown() directly.

I've discovered that in the second unit test, the initialize method isn't called. Is this a special method that's only called once per 'application run'? Should I not be setting default values there?

Well my hunch was correct. It turns out that I was right, and that initialize is only called once per request according to the docs, though shouldn't each unit test be considered a new test?

The initialize() method is only called once during the request, it’s intended to perform initializations that apply for all instances of the model created within the application. If you want to perform initialization tasks for every instance created you can use the onConstruct() method:

This sort of says the same thing though. For what should I be using initialize for and onConstruct?

edited Jul '17

Initialize - for setting relations between models, for setting keeping snapshots etc. onConstruct, for things which will be called on each model construction. For example:

for($i =0; $i < 10000; $i++) {
    $model = new SomeModel();
}

If you have both onConstruct and initialize, initialize will be called only once, onConstruct will be called on each model creation.

For unit tests, you might want to stick with onConstruct() as that method acts as __construct() in native PHP.

Well my hunch was correct. It turns out that I was right, and that initialize is only called once per request according to the docs, though shouldn't each unit test be considered a new test?

The initialize() method is only called once during the request, it’s intended to perform initializations that apply for all instances of the model created within the application. If you want to perform initialization tasks for every instance created you can use the onConstruct() method:

This sort of says the same thing though. For what should I be using initialize for and onConstruct?

Oh thank you! It's a learning experience!

Can I modify the docs to update that bit of really useful information, or do I have to submit an issue about the docs not giving an example such as relationships being set up in initialize and default values in onConstruct?

But it's telling it exactly here:

The initialize() method is only called once during the request, it’s intended to perform initializations that apply for all instances of the model created within the application. If you want to perform initialization tasks for every instance created you can use the onConstruct() method:

Here is very clear that is only called once durign the request. What's more is needed?

edited Jul '17

it’s intended to perform initializations that apply for all instances of the model created within the application.

initialize is to perform initializations that apply to all instances. this - in my mind- conjures up setting default values

If you want to perform initialization tasks for every instance created you can use the onConstruct() method:

onConstruct is to perform initializations that apply to all instances.

I would think something like:

initialize is called once per request (note: a separate unit test is not a separate request), whereas onConstruct is called for each object created. The initialize method is the place to put your model relationships, whereas the onConstruct method is where you can put your model's initial default values for each instance.