From a0d3ad187542e95b5223465d040de1cbffda0878 Mon Sep 17 00:00:00 2001 From: Rob Ingram Date: Tue, 23 Aug 2016 10:42:14 +1200 Subject: [PATCH] Change order of fixtures in example * Make the document explicit about the definition of objects before they are referenced. --- .../06_Testing/04_Fixtures.md | 76 ++++++++++--------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/docs/en/02_Developer_Guides/06_Testing/04_Fixtures.md b/docs/en/02_Developer_Guides/06_Testing/04_Fixtures.md index 3db2bd5dd..b3de024bc 100644 --- a/docs/en/02_Developer_Guides/06_Testing/04_Fixtures.md +++ b/docs/en/02_Developer_Guides/06_Testing/04_Fixtures.md @@ -3,20 +3,20 @@ summary: Populate test databases with fake seed data. # Fixtures -To test functionality correctly, we must use consistent data. If we are testing our code with the same data each -time, we can trust our tests to yield reliable results and to identify when the logic changes. Each test run in +To test functionality correctly, we must use consistent data. If we are testing our code with the same data each +time, we can trust our tests to yield reliable results and to identify when the logic changes. Each test run in SilverStripe starts with a fresh database containing no records. `Fixtures` provide a way to describe the initial data -to load into the database. The [api:SapphireTest] class takes care of populating a test database with data from +to load into the database. The [api:SapphireTest] class takes care of populating a test database with data from fixtures - all we have to do is define them. -Fixtures are defined in `YAML`. `YAML` is a markup language which is deliberately simple and easy to read, so it is +Fixtures are defined in `YAML`. `YAML` is a markup language which is deliberately simple and easy to read, so it is ideal for fixture generation. Say we have the following two DataObjects: :::php 'Varchar(255)' ); @@ -43,6 +43,13 @@ We can represent multiple instances of them in `YAML` as follows: **mysite/tests/fixtures.yml** :::yml + Team: + hurricanes: + Name: The Hurricanes + Origin: Wellington + crusaders: + Name: The Crusaders + Origin: Canterbury Player: john: Name: John @@ -53,18 +60,11 @@ We can represent multiple instances of them in `YAML` as follows: jack: Name: Jack Team: =>Team.crusaders - Team: - hurricanes: - Name: The Hurricanes - Origin: Wellington - crusaders: - Name: The Crusaders - Origin: Canterbury -This `YAML` is broken up into three levels, signified by the indentation of each line. In the first level of +This `YAML` is broken up into three levels, signified by the indentation of each line. In the first level of indentation, `Player` and `Team`, represent the class names of the objects we want to be created. -The second level, `john`/`joe`/`jack` & `hurricanes`/`crusaders`, are **identifiers**. Each identifier you specify +The second level, `john`/`joe`/`jack` & `hurricanes`/`crusaders`, are **identifiers**. Each identifier you specify represents a new object and can be referenced in the PHP using `objFromFixture` :::php @@ -72,10 +72,10 @@ represents a new object and can be referenced in the PHP using `objFromFixture` The third and final level represents each individual object's fields. -A field can either be provided with raw data (such as the names for our Players), or we can define a relationship, as +A field can either be provided with raw data (such as the names for our Players), or we can define a relationship, as seen by the fields prefixed with `=>`. -Each one of our Players has a relationship to a Team, this is shown with the `Team` field for each `Player` being set +Each one of our Players has a relationship to a Team, this is shown with the `Team` field for each `Player` being set to `=>Team.` followed by a team name.
@@ -84,10 +84,14 @@ sets the `has_one` relationship for John with with the `Team` object `hurricanes
-Note that we use the name of the relationship (Team), and not the name of the +Note that we use the name of the relationship (Team), and not the name of the database field (TeamID).
+
+Also be aware the target of a relationship must be defined before it is referenced, for example the `hurricanes` team must appear in the fixture file before the line `Team: =>Team.hurricanes`. +
+ This style of relationship declaration can be used for any type of relationship (i.e `has_one`, `has_many`, `many_many`). We can also declare the relationships conversely. Another way we could write the previous example is: @@ -110,8 +114,8 @@ We can also declare the relationships conversely. Another way we could write the Origin: Canterbury Players: =>Player.joe,=>Player.jack -The database is populated by instantiating `DataObject` objects and setting the fields declared in the `YAML`, then -calling `write()` on those objects. Take for instance the `hurricances` record in the `YAML`. It is equivalent to +The database is populated by instantiating `DataObject` objects and setting the fields declared in the `YAML`, then +calling `write()` on those objects. Take for instance the `hurricances` record in the `YAML`. It is equivalent to writing: :::php @@ -125,18 +129,18 @@ writing: $team->Players()->add($john);
-As the YAML fixtures will call `write`, any `onBeforeWrite()` or default value logic will be executed as part of the +As the YAML fixtures will call `write`, any `onBeforeWrite()` or default value logic will be executed as part of the test.
### Defining many_many_extraFields -`many_many` relations can have additional database fields attached to the relationship. For example we may want to +`many_many` relations can have additional database fields attached to the relationship. For example we may want to declare the role each player has in the team. :::php class Player extends DataObject { - + private static $db = array ( 'Name' => 'Varchar(255)' ); @@ -160,7 +164,7 @@ declare the role each player has in the team. "Players" => array( "Role" => "Varchar" ) - ); + ); } To provide the value for the `many_many_extraField` use the YAML list syntax. @@ -176,13 +180,13 @@ To provide the value for the `many_many_extraField` use the YAML list syntax. Team: hurricanes: Name: The Hurricanes - Players: + Players: - =>Player.john: Role: Captain crusaders: Name: The Crusaders - Players: + Players: - =>Player.joe: Role: Captain - =>Player.jack: @@ -190,20 +194,20 @@ To provide the value for the `many_many_extraField` use the YAML list syntax. ## Fixture Factories -While manually defined fixtures provide full flexibility, they offer very little in terms of structure and convention. +While manually defined fixtures provide full flexibility, they offer very little in terms of structure and convention. -Alternatively, you can use the [api:FixtureFactory] class, which allows you to set default values, callbacks on object +Alternatively, you can use the [api:FixtureFactory] class, which allows you to set default values, callbacks on object creation, and dynamic/lazy value setting.
SapphireTest uses FixtureFactory under the hood when it is provided with YAML based fixtures.
-The idea is that rather than instantiating objects directly, we'll have a factory class for them. This factory can have -*blueprints* defined on it, which tells the factory how to instantiate an object of a specific type. Blueprints need a +The idea is that rather than instantiating objects directly, we'll have a factory class for them. This factory can have +*blueprints* defined on it, which tells the factory how to instantiate an object of a specific type. Blueprints need a name, which is usually set to the class it creates such as `Member` or `Page`. -Blueprints are auto-created for all available DataObject subclasses, you only need to instantiate a factory to start +Blueprints are auto-created for all available DataObject subclasses, you only need to instantiate a factory to start using them. :::php @@ -219,7 +223,7 @@ In order to create an object with certain properties, just add a third argument: ));
-It is important to remember that fixtures are referenced by arbitrary identifiers ('hurricanes'). These are internally +It is important to remember that fixtures are referenced by arbitrary identifiers ('hurricanes'). These are internally mapped to their database identifiers.
@@ -241,7 +245,7 @@ name, we can set the default to be `Unknown Team`. ### Dependent Properties -Values can be set on demand through anonymous functions, which can either generate random defaults, or create composite +Values can be set on demand through anonymous functions, which can either generate random defaults, or create composite values based on other fixture data. :::php @@ -258,7 +262,7 @@ values based on other fixture data. ### Relations -Model relations can be expressed through the same notation as in the YAML fixture format described earlier, through the +Model relations can be expressed through the same notation as in the YAML fixture format described earlier, through the `=>` prefix on data values. :::php @@ -268,7 +272,7 @@ Model relations can be expressed through the same notation as in the YAML fixtur #### Callbacks -Sometimes new model instances need to be modified in ways which can't be expressed in their properties, for example to +Sometimes new model instances need to be modified in ways which can't be expressed in their properties, for example to publish a page, which requires a method call. :::php @@ -287,8 +291,8 @@ Available callbacks: ### Multiple Blueprints -Data of the same type can have variations, for example forum members vs. CMS admins could both inherit from the `Member` -class, but have completely different properties. This is where named blueprints come in. By default, blueprint names +Data of the same type can have variations, for example forum members vs. CMS admins could both inherit from the `Member` +class, but have completely different properties. This is where named blueprints come in. By default, blueprint names equal the class names they manage. :::php