This guide is for those who want to have a better understanding of the library internals and how to contribute. The code and the tests are the best documentation you will find, so the guide only aims at introducing the higher picture of the library mechanisms.
- Differences between 2.x and 3.x
- Architecture
- FixtureBuilder
- Generator
- Expression Language
- Contributing
- Testing
- Profiling
Main differences between 2.x and 3.x:
- The persistence layer has been removed
- Rewrite of the API to make it more extensible and more robust
- Change in the architecture to address some limitations found in 2.x
The two entry points of the library are the DataLoader
and FileLoader
:
Alice's goal is to render a PHP array containing a description of objects and parameters (with support for injected external objects
and parameters) into a set of objects called ObjectSet
.
In DataLoader
, the main components are:
FixtureBuilder
: denormalizes the given PHP array into a comprehensible set of data calledFixtureSet
Generator
: generates the objects and resolve the parameters described inFixtureSet
to generate anObjectSet
FixtureBuilder
is composed of two components: Denormalizer
and ExpressionLanguage
.
Denormalizer
transforms the input data array with the injected values into a collection of Fixture
, which describes an object to
generate with a set of parameters.
ExpressionLanguage
is the component used by the Denormalizer
to parse the values such as @user<current()>
, i.e.
the Alice DSL interpreter.
The result FixtureSet
is always invariant: reloading the same set of data will always result in the same result, hence
is cacheable.
The Generator
transforms a FixtureSet
(composed of Fixture
, parameters, injected objects, and
injected parameters) into an ObjectSet
, which is a collection of PHP objects and parameters. Because some data are
generated "randomly" thanks to Faker, a FixtureSet
will always give a different
ObjectSet
. If there is no dynamic data, the result will always be the same. If Faker is seeded
with null
, the data will be generated more or less randomly. For a given seed, though,
the data generated will always be the same.
The data is generated in the following order:
- Fixture Resolution (
FixtureSet
):- Resolve the parameters: it is assumed the injected parameters are already resolved. Existing parameters are overriden by the local ones if they conflict.
- Resolve the fixtures: a fixture may have flags (for example, to support
templates).
This resolution step is where it is possible to alter the collection of fixtures depending on the flags. In the
templates example, this is the step where a
dummy
fixture inheriting from abase_dummy
will inherit the properties ofbase_dummy
, andbase_dummy
will be removed of the list of fixtures (templates should not be generated).
- Instantiation: This when all fixtures will be instantiated. The
instantiation attempts to account for the order. For example, if
second_dummy
is being instantiated but requiresfirst_dummy
to exist, the instantiator will instantiatefirst_dummy
before resuming the instantiation ofsecond_dummy
. - Hydration: This is when all the property values will be set.
- Calling: Additional function calls can be made on the PHP objects after instantiation and hydration.
During the instantiation, hydration or calling process, values may be passed. Those values may be a reference to another
fixture, a parameter, a static value, but or a value that must be generated via faker. For example,
<name()>
will result in a random name. Those values are always resolved on the fly by a ValueResolver
.
To see more about the fixture lifecycle, please check #388.
For more details regarding a class, the easiest way is to check the code itself and the tests.
As already mentioned, Alice ships with an Expression Language, which interprets values such as @user*
or
<current()>
. The complete list of supported features can be found in ParserIntegrationTest
with the original RFC.
The project uses PHPUnit for tests. The library also includes framework bridges (like for Symfony), which amounts to registering the right services with the right properties (like tags and configuration) to the framework Dependency Injection Container. Any other framework special features should be handled in another library, bundle, module etc.
To avoid any conflicts, the framework dependencies used by the bridges are installed in dedicated folders thanks to
bamarni bin composer plugin and theofidry inheritance composer plugin. As a result, if you want to run the
tests for Symfony, you must run the tests with phpunit_symfony.xml.dist
instead of phpunit.xml.dist
.
To run the tests, simply run bin/tests.sh
.
The tests should be descriptive and are "testdox friendly" i.e. if you are using the testdox option, you will get something like:
A Profiling of different scenari is done with Blackfire. The scenario can be found under profiling
. If you wish
to run them, you can try to simply run bin/profiling.sh
. You may however have to touch some elements of the
blackfire configuration (see the profiling/scenarioX/blackfire.php
files).