mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Don't think the syntax highlighter likes my indentation with spaces.
This commit is contained in:
parent
3e5f788ddc
commit
6145e5914b
@ -42,7 +42,7 @@ URLs. Here is an example from the subsites module:
|
||||
$this->assertTrue(strpos($response3->getBody(), '<form') === false);
|
||||
$this->assertTrue(strpos($response3->getBody(), '<head') === false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
We are using a new static method here: **Director::test($url, $postVars, $sessionObj)**
|
||||
@ -64,6 +64,6 @@ We can use string processing on the body of the response to then see if it fits
|
||||
If you're testing for natural language responses like error messages, make sure to use [i18n](/topics/i18n) translations through
|
||||
the *_t()* method to avoid tests failing when i18n is enabled.
|
||||
|
||||
Note that for a more highlevel testing approach, SilverStripe also supports
|
||||
Note that for a more highlevel testing approach, SilverStripe also supports
|
||||
[behaviour-driven testing through Behat](https://github.com/silverstripe-labs/silverstripe-behat-extension). It interacts
|
||||
directly with your website or CMS interface by remote controlling an actual browser, driven by natural language assertions.
|
@ -16,48 +16,48 @@ so it is ideal for fixture generation.
|
||||
|
||||
Say we have the following two DataObjects:
|
||||
|
||||
:::php
|
||||
class Player extends DataObject {
|
||||
static $db = array (
|
||||
'Name' => 'Varchar(255)'
|
||||
);
|
||||
:::php
|
||||
class Player extends DataObject {
|
||||
static $db = array (
|
||||
'Name' => 'Varchar(255)'
|
||||
);
|
||||
|
||||
static $has_one = array(
|
||||
'Team' => 'Team'
|
||||
);
|
||||
}
|
||||
static $has_one = array(
|
||||
'Team' => 'Team'
|
||||
);
|
||||
}
|
||||
|
||||
class Team extends DataObject {
|
||||
static $db = array (
|
||||
'Name' => 'Varchar(255)',
|
||||
'Origin' => 'Varchar(255)'
|
||||
);
|
||||
class Team extends DataObject {
|
||||
static $db = array (
|
||||
'Name' => 'Varchar(255)',
|
||||
'Origin' => 'Varchar(255)'
|
||||
);
|
||||
|
||||
static $has_many = array(
|
||||
'Players' => 'Player'
|
||||
);
|
||||
}
|
||||
static $has_many = array(
|
||||
'Players' => 'Player'
|
||||
);
|
||||
}
|
||||
|
||||
We can represent multiple instances of them in `YAML` as follows:
|
||||
|
||||
:::yml
|
||||
Player:
|
||||
john:
|
||||
Name: John
|
||||
Team: =>Team.hurricanes
|
||||
joe:
|
||||
Name: Joe
|
||||
Team: =>Team.crusaders
|
||||
jack:
|
||||
Name: Jack
|
||||
Team: =>Team.crusaders
|
||||
Team:
|
||||
hurricanes:
|
||||
Name: The Hurricanes
|
||||
Origin: Wellington
|
||||
crusaders:
|
||||
Name: The Crusaders
|
||||
Origin: Bay of Plenty
|
||||
:::yml
|
||||
Player:
|
||||
john:
|
||||
Name: John
|
||||
Team: =>Team.hurricanes
|
||||
joe:
|
||||
Name: Joe
|
||||
Team: =>Team.crusaders
|
||||
jack:
|
||||
Name: Jack
|
||||
Team: =>Team.crusaders
|
||||
Team:
|
||||
hurricanes:
|
||||
Name: The Hurricanes
|
||||
Origin: Wellington
|
||||
crusaders:
|
||||
Name: The Crusaders
|
||||
Origin: Bay of Plenty
|
||||
|
||||
Our `YAML` is broken up into three levels, signified by the indentation of each line.
|
||||
In the first level of indentation, `Player` and `Team`,
|
||||
@ -86,23 +86,23 @@ This style of relationship declaration can be used for both a `has-one` and a `m
|
||||
For `many-many` relationships, we specify a comma separated list of values.
|
||||
For example we could just as easily write the above as:
|
||||
|
||||
:::yml
|
||||
Player:
|
||||
john:
|
||||
Name: John
|
||||
joe:
|
||||
Name: Joe
|
||||
jack:
|
||||
Name: Jack
|
||||
Team:
|
||||
hurricanes:
|
||||
Name: The Hurricanes
|
||||
Origin: Wellington
|
||||
Players: =>Player.john
|
||||
crusaders:
|
||||
Name: The Crusaders
|
||||
Origin: Bay of Plenty
|
||||
Players: =>Player.joe,=>Player.jack
|
||||
:::yml
|
||||
Player:
|
||||
john:
|
||||
Name: John
|
||||
joe:
|
||||
Name: Joe
|
||||
jack:
|
||||
Name: Jack
|
||||
Team:
|
||||
hurricanes:
|
||||
Name: The Hurricanes
|
||||
Origin: Wellington
|
||||
Players: =>Player.john
|
||||
crusaders:
|
||||
Name: The Crusaders
|
||||
Origin: Bay of Plenty
|
||||
Players: =>Player.joe,=>Player.jack
|
||||
|
||||
A crucial thing to note is that **the YAML file specifies DataObjects, not database records**.
|
||||
The database is populated by instantiating DataObject objects and setting the fields declared in the YML,
|
||||
@ -123,18 +123,18 @@ One common example here is publishing pages (page fixtures aren't published by d
|
||||
You can always resort to creating objects manually in the test setup phase.
|
||||
Since the test database is cleared on every test method, you'll get a fresh set of test instances every time.
|
||||
|
||||
:::php
|
||||
class SiteTreeTest extends SapphireTest {
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
:::php
|
||||
class SiteTreeTest extends SapphireTest {
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
for($i=0; $i<100; $i++) {
|
||||
$page = new Page(array('Title' => "Page $i"));
|
||||
$page->write();
|
||||
$page->publish('Stage', 'Live');
|
||||
}
|
||||
}
|
||||
}
|
||||
for($i=0; $i<100; $i++) {
|
||||
$page = new Page(array('Title' => "Page $i"));
|
||||
$page->write();
|
||||
$page->publish('Stage', 'Live');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
## Fixture Factories
|
||||
|
||||
@ -156,69 +156,69 @@ This factory can have so called "blueprints" defined on it, which tells the fact
|
||||
Since blueprints are auto-created for all available DataObject subclasses,
|
||||
you only need to instantiate a factory to start using it.
|
||||
|
||||
:::php
|
||||
$factory = Injector::inst()->create('FixtureFactory');
|
||||
$obj = $factory->createObject('MyClass', 'myobj1');
|
||||
:::php
|
||||
$factory = Injector::inst()->create('FixtureFactory');
|
||||
$obj = $factory->createObject('MyClass', 'myobj1');
|
||||
|
||||
It is important to remember that fixtures are referenced by arbitrary
|
||||
identifiers ('myobj1'). These are internally mapped to their database identifiers.
|
||||
|
||||
:::
|
||||
$databaseId = $factory->getId('MyClass', 'myobj1');
|
||||
:::php
|
||||
$databaseId = $factory->getId('MyClass', 'myobj1');
|
||||
|
||||
In order to create an object with certain properties, just add a second argument:
|
||||
|
||||
:::php
|
||||
$obj = $factory->createObject('MyClass', 'myobj1', array('MyProperty' => 'My Value'));
|
||||
:::php
|
||||
$obj = $factory->createObject('MyClass', 'myobj1', array('MyProperty' => 'My Value'));
|
||||
|
||||
#### Default Properties
|
||||
|
||||
Blueprints can be overwritten in order to customize their behaviour,
|
||||
for example with default properties in case none are passed into `createObject()`.
|
||||
|
||||
:::php
|
||||
$factory->define('MyObject', array(
|
||||
'MyProperty' => 'My Default Value'
|
||||
));
|
||||
:::php
|
||||
$factory->define('MyObject', array(
|
||||
'MyProperty' => 'My Default Value'
|
||||
));
|
||||
|
||||
#### Dependent Properties
|
||||
|
||||
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
|
||||
$factory->define('Member', array(
|
||||
'Email' => function($obj, $data, $fixtures) {
|
||||
if(isset($data['FirstName']) {
|
||||
$obj->Email = strtolower($data['FirstName']) . '@example.org';
|
||||
}
|
||||
},
|
||||
'Score' => function($obj, $data, $fixtures) {
|
||||
$obj->Score = rand(0,10);
|
||||
}
|
||||
));
|
||||
:::php
|
||||
$factory->define('Member', array(
|
||||
'Email' => function($obj, $data, $fixtures) {
|
||||
if(isset($data['FirstName']) {
|
||||
$obj->Email = strtolower($data['FirstName']) . '@example.org';
|
||||
}
|
||||
},
|
||||
'Score' => function($obj, $data, $fixtures) {
|
||||
$obj->Score = rand(0,10);
|
||||
}
|
||||
));
|
||||
|
||||
#### Relations
|
||||
|
||||
Model relations can be expressed through the same notation as in the YAML fixture format
|
||||
described earlier, through the `=>` prefix on data values.
|
||||
|
||||
:::php
|
||||
$obj = $factory->createObject('MyObject', 'myobj1', array(
|
||||
'MyHasManyRelation' => '=>MyOtherObject.obj1,=>MyOtherObject.obj2'
|
||||
));
|
||||
:::php
|
||||
$obj = $factory->createObject('MyObject', 'myobj1', array(
|
||||
'MyHasManyRelation' => '=>MyOtherObject.obj1,=>MyOtherObject.obj2'
|
||||
));
|
||||
|
||||
#### Callbacks
|
||||
|
||||
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
|
||||
$blueprint = Injector::inst()->create('FixtureBlueprint', 'Member');
|
||||
$blueprint->addCallback('afterCreate', function($obj, $identifier, $data, $fixtures) {
|
||||
$obj->publish('Stage', 'Live');
|
||||
});
|
||||
$page = $factory->define('Page', $blueprint);
|
||||
:::php
|
||||
$blueprint = Injector::inst()->create('FixtureBlueprint', 'Member');
|
||||
$blueprint->addCallback('afterCreate', function($obj, $identifier, $data, $fixtures) {
|
||||
$obj->publish('Stage', 'Live');
|
||||
});
|
||||
$page = $factory->define('Page', $blueprint);
|
||||
|
||||
Available callbacks:
|
||||
|
||||
@ -232,43 +232,43 @@ 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
|
||||
$memberBlueprint = Injector::inst()->create('FixtureBlueprint', 'Member', 'Member');
|
||||
$adminBlueprint = Injector::inst()->create('FixtureBlueprint', 'AdminMember', 'Member');
|
||||
$adminBlueprint->addCallback('afterCreate', function($obj, $identifier, $data, $fixtures) {
|
||||
if(isset($fixtures['Group']['admin'])) {
|
||||
$adminGroup = Group::get()->byId($fixtures['Group']['admin']);
|
||||
$obj->Groups()->add($adminGroup);
|
||||
}
|
||||
});
|
||||
:::php
|
||||
$memberBlueprint = Injector::inst()->create('FixtureBlueprint', 'Member', 'Member');
|
||||
$adminBlueprint = Injector::inst()->create('FixtureBlueprint', 'AdminMember', 'Member');
|
||||
$adminBlueprint->addCallback('afterCreate', function($obj, $identifier, $data, $fixtures) {
|
||||
if(isset($fixtures['Group']['admin'])) {
|
||||
$adminGroup = Group::get()->byId($fixtures['Group']['admin']);
|
||||
$obj->Groups()->add($adminGroup);
|
||||
}
|
||||
});
|
||||
|
||||
$member = $factory->createObject('Member'); // not in admin group
|
||||
$admin = $factory->createObject('AdminMember'); // in admin group
|
||||
$member = $factory->createObject('Member'); // not in admin group
|
||||
$admin = $factory->createObject('AdminMember'); // in admin group
|
||||
|
||||
### Full Test Example
|
||||
|
||||
:::php
|
||||
class MyObjectTest extends SapphireTest {
|
||||
:::php
|
||||
class MyObjectTest extends SapphireTest {
|
||||
|
||||
protected $factory;
|
||||
protected $factory;
|
||||
|
||||
function __construct() {
|
||||
parent::__construct();
|
||||
function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$factory = Injector::inst()->create('FixtureFactory');
|
||||
// Defines a "blueprint" for new objects
|
||||
$factory->define('MyObject', array(
|
||||
'MyProperty' => 'My Default Value'
|
||||
));
|
||||
$this->factory = $factory;
|
||||
}
|
||||
$factory = Injector::inst()->create('FixtureFactory');
|
||||
// Defines a "blueprint" for new objects
|
||||
$factory->define('MyObject', array(
|
||||
'MyProperty' => 'My Default Value'
|
||||
));
|
||||
$this->factory = $factory;
|
||||
}
|
||||
|
||||
function testSomething() {
|
||||
$MyObjectObj = $this->factory->createObject(
|
||||
'MyObject',
|
||||
array('MyOtherProperty' => 'My Custom Value')
|
||||
);
|
||||
// $myPageObj->MyProperty = My Default Value
|
||||
// $myPageObj->MyOtherProperty = My Custom Value
|
||||
}
|
||||
}
|
||||
function testSomething() {
|
||||
$MyObjectObj = $this->factory->createObject(
|
||||
'MyObject',
|
||||
array('MyOtherProperty' => 'My Custom Value')
|
||||
);
|
||||
// $myPageObj->MyProperty = My Default Value
|
||||
// $myPageObj->MyOtherProperty = My Custom Value
|
||||
}
|
||||
}
|
||||
|
@ -23,21 +23,21 @@ Unit tests are not included in the normal SilverStripe downloads, you are expect
|
||||
|
||||
Once you've got the project up and running, check out the additional requirements to run unit tests:
|
||||
|
||||
composer update --dev
|
||||
composer update --dev
|
||||
|
||||
This will install (among other things) the [PHPUnit](http://www.phpunit.de/) dependency, which is the framework we're
|
||||
building our unit tests on. Composer installs it alongside the required PHP classes into the `vendor/bin/` directory.
|
||||
You can either use it through its full path (`vendor/bin/phpunit`), or symlink it into the root directory of your website:
|
||||
|
||||
ln -s vendor/bin/phpunit phpunit
|
||||
ln -s vendor/bin/phpunit phpunit
|
||||
|
||||
### Via PEAR
|
||||
|
||||
Alternatively, you can check out PHPUnit globally via the PEAR packanage manager
|
||||
([instructions](https://github.com/sebastianbergmann/phpunit/)).
|
||||
|
||||
pear config-set auto_discover 1
|
||||
pear install pear.phpunit.de/PHPUnit
|
||||
pear config-set auto_discover 1
|
||||
pear install pear.phpunit.de/PHPUnit
|
||||
|
||||
## Configuration
|
||||
|
||||
@ -90,20 +90,20 @@ Tutorials and recipes for creating tests using the SilverStripe framework:
|
||||
|
||||
The `phpunit` binary should be used from the root directory of your website.
|
||||
|
||||
# Runs all tests defined in phpunit.xml
|
||||
phpunit
|
||||
# Runs all tests defined in phpunit.xml
|
||||
phpunit
|
||||
|
||||
# Run all tests of a specific module
|
||||
phpunit framework/tests/
|
||||
# Run all tests of a specific module
|
||||
phpunit framework/tests/
|
||||
|
||||
# Run specific tests within a specific module
|
||||
phpunit framework/tests/filesystem
|
||||
# Run specific tests within a specific module
|
||||
phpunit framework/tests/filesystem
|
||||
|
||||
# Run a specific test
|
||||
phpunit framework/tests/filesystem/FolderTest.php
|
||||
# Run a specific test
|
||||
phpunit framework/tests/filesystem/FolderTest.php
|
||||
|
||||
# Run tests with optional `$_GET` parameters (you need an empty second argument)
|
||||
phpunit framework/tests '' flush=all
|
||||
# Run tests with optional `$_GET` parameters (you need an empty second argument)
|
||||
phpunit framework/tests '' flush=all
|
||||
|
||||
All command-line arguments are documented on
|
||||
[phpunit.de](http://www.phpunit.de/manual/current/en/textui.html).
|
||||
@ -115,20 +115,20 @@ The [sake](/topics/commandline) executable that comes with SilverStripe can trig
|
||||
While the custom test runner a handy tool, its also more limited than using `phpunit` directly,
|
||||
particularly around formatting test output.
|
||||
|
||||
# Run all tests
|
||||
sake dev/tests/all
|
||||
# Run all tests
|
||||
sake dev/tests/all
|
||||
|
||||
# Run all tests of a specific module (comma-separated)
|
||||
sake dev/tests/module/framework,cms
|
||||
# Run all tests of a specific module (comma-separated)
|
||||
sake dev/tests/module/framework,cms
|
||||
|
||||
# Run specific tests (comma-separated)
|
||||
sake dev/tests/FolderTest,OtherTest
|
||||
# Run specific tests (comma-separated)
|
||||
sake dev/tests/FolderTest,OtherTest
|
||||
|
||||
# Run tests with optional `$_GET` parameters
|
||||
sake dev/tests/all flush=all
|
||||
# Run tests with optional `$_GET` parameters
|
||||
sake dev/tests/all flush=all
|
||||
|
||||
# Skip some tests
|
||||
sake dev/tests/all SkipTests=MySkippedTest
|
||||
# Skip some tests
|
||||
sake dev/tests/all SkipTests=MySkippedTest
|
||||
|
||||
### Via Web Browser
|
||||
|
||||
@ -136,4 +136,4 @@ Executing tests from the command line is recommended, since it most closely refl
|
||||
test runs in any automated testing environments. If for some reason you don't have
|
||||
access to the command line, you can also run tests through the browser.
|
||||
|
||||
http://localhost/dev/tests
|
||||
http://localhost/dev/tests
|
||||
|
@ -8,19 +8,19 @@ For this to work, you need to send emails using the `Email` class,
|
||||
which is generally the way that we recommend you send emails in your SilverStripe application.
|
||||
Here is a simple example of how you might do this:
|
||||
|
||||
:::php
|
||||
$e = new Email();
|
||||
$e->To = "someone@example.com";
|
||||
$e->Subject = "Hi there";
|
||||
$e->Body = "I just really wanted to email you and say hi.";
|
||||
$e->send();
|
||||
:::php
|
||||
$e = new Email();
|
||||
$e->To = "someone@example.com";
|
||||
$e->Subject = "Hi there";
|
||||
$e->Body = "I just really wanted to email you and say hi.";
|
||||
$e->send();
|
||||
|
||||
Normally, the `send()` method would send an email using PHP's `mail()` function.
|
||||
However, if you are running a `[api:SapphireTest]` test, then it holds off actually sending the email,
|
||||
and instead lets you assert that an email was sent using this method.
|
||||
|
||||
:::php
|
||||
$this->assertEmailSent("someone@example.com", null, "/th.*e$/");
|
||||
:::php
|
||||
$this->assertEmailSent("someone@example.com", null, "/th.*e$/");
|
||||
|
||||
The arguments are `$to`, `$from`, `$subject`, `$body`, and can take one of the three following types:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user