2019-02-05 01:27:13 +00:00
theme: poster, 8
2017-10-05 06:53:55 +00:00
autoscale: true
build-lists: true
2018-06-15 06:43:54 +00:00
header-emphasis: #53B0EB
header: alignment(left)
text: alignment(left)
text-emphasis: #53B0EB
2019-02-05 01:27:13 +00:00
code: Monaco, #6699FF , #999999 , #6666FF , #66FF66 , #66FF66 , line-height(1.3)
2018-06-15 06:43:54 +00:00
[.header: alignment(center)]
2017-10-05 06:53:55 +00:00
2017-10-21 12:56:01 +00:00
![](images/title.png)
2017-10-05 06:53:55 +00:00
2018-06-15 06:43:54 +00:00
# _TDD:_ Test <br>Driven Drupal
2017-10-05 06:53:55 +00:00
---
2019-02-05 01:27:13 +00:00
[.header: alignment(center)]
## [fit] opdavi.es/_tdd-test-driven-drupal_
^ View on the website or click through to Speakerdeck
---
[.background-color: #FFFFFF ]
[.header: #111111 , alignment(left)]
## Diamond sponsor
![inline 100% ](images/ddd-2.jpeg )
---
[.background-color: #FFFFFF ]
[.header: #111111 , alignment(left)]
## Platinum sponsors
![inline 100% ](images/ddd-3.jpeg )
---
[.background-color: #FFFFFF ]
[.header: #111111 , alignment(left)]
## Gold sponsors
![inline 100% ](images/ddd-4.jpeg )
---
![fit ](images/ddd-5.jpg )
---
[.build-lists: false]
- Module and theme developers
- Want to know more about automated testing
- Looking to start writing your first tests
- Drupal 8
- PHPUnit
---
- Why write tests, and what to test
- Types of tests
- How to run tests
- Real life example
- Building a new module with TDD
---
2018-06-15 06:43:54 +00:00
[.background-color: #FFFFFF ]
2017-11-08 06:56:37 +00:00
[.build-lists: false]
2018-06-15 06:43:54 +00:00
[.header: #111111 ]
[.text: #111111 , alignment(left)]
2019-02-05 01:27:13 +00:00
![right 800% ](../images/me-phpnw.png )
2018-06-15 06:43:54 +00:00
2019-02-05 01:27:13 +00:00
- Full Stack Web Developer & System Administrator
2018-06-15 06:43:54 +00:00
- Senior Developer at Microserve
- Part-time freelancer
- Acquia certified Drupal 8 Grand Master
- Drupal 7 & 8 core contributor
2019-02-05 01:27:13 +00:00
- Symfony, Laravel, ~~Silex,~~ Sculpin
- @opdavies
2018-06-15 06:43:54 +00:00
- www.oliverdavies.uk
2017-11-08 06:56:37 +00:00
2018-06-15 06:43:54 +00:00
^ Work at Microserve.
Maintain Drupal modules, PHP CLI tools and libraries
Blog on my website
2017-10-05 06:53:55 +00:00
---
2019-02-05 01:27:13 +00:00
[.build-lists: false]
- oliverdavies.uk/_talks_
- oliverdavies.uk/_twitter_
- oliverdavies.uk/_drupal_
- oliverdavies.uk/_github_
^ Example code on GitHub
---
[.background-color: #FFFFFF ]
[.text: #111111 , alignment(left)]
![right 100% ](../images/microserve-light.png )
- https://microserve.io
- https://www.drupal.org/microserve
- https://github.com/microserve-io
- https://twitter.com/microserveltd
- https://www.linkedin.com/company/microserve-ltd
---
2018-06-15 06:43:54 +00:00
[.header: alignment(center)]
2017-10-05 06:53:55 +00:00
2018-06-15 06:43:54 +00:00
## test_driven_drupal_.com_
---
[.header: alignment(center)]
2019-02-05 01:27:13 +00:00
## Write custom modules and themes _for clients_
2018-06-15 06:43:54 +00:00
---
[.header: alignment(center)]
2019-02-05 01:27:13 +00:00
## Occassionally <br>contribute _to core_
2018-06-15 06:43:54 +00:00
---
2017-10-05 06:53:55 +00:00
2018-06-15 06:43:54 +00:00
[.header: alignment(center)]
2019-02-05 01:27:13 +00:00
## Maintain and contribute to _contrib projects_
2017-11-08 06:56:37 +00:00
---
2018-06-15 06:43:54 +00:00
[.background-color: #FFFFFF ]
![inline 150% ](images/timmillwood-ono.png )
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
## _Override Node Options_
- Become maintainer in 2012
- Had some existing tests
- Used on _11,046 sites_ in October 2012 (_84_ D5, _7,094_ D6, _3,868_ D7)
- Used on _29,023 sites_ in June 2018 (_9_ D5, _1,853_ D6, _23,602_ D7, _3,559_ D8)
2019-02-05 01:27:13 +00:00
- _#236_ most used module on Drupal.org
2018-06-15 06:43:54 +00:00
- Crucial to preventing regressions when adding new features or fixing bugs
^ Preventing regressions in my additions but also user submitted patches
2019-02-05 01:27:13 +00:00
First module I ported to Drupal 8, aided by tests
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
---
[.header: alignment(center)]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
## _Why_ write tests?
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
## _Why write tests?_
2017-10-21 12:56:01 +00:00
- Catch bugs earlier
2019-02-05 01:27:13 +00:00
- Peace of mind
2017-10-21 12:56:01 +00:00
- Prevent regressions
- Write less code
- Documentation
2018-06-15 06:43:54 +00:00
- Drupal core requirement - _<https://www.drupal.org/core/gates#testing>_
2017-10-21 12:56:01 +00:00
- More important with regular D8 releases
^ Dave Liddament talk - better and cheaper to catch bugs earlier (e.g. whilst developing rather than after it's been released)
Refer to tests when writing implementation code
ONO merge conflict
---
2018-06-15 06:43:54 +00:00
## _Core Testing Gate_
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
- New features should be accompanied by automated tests.
- If the feature does not have an implementation, provide a test implementation.
- Bug fixes should be accompanied by changes to a test (either modifying an existing test case or adding a new one) that demonstrate the bug.
2017-10-21 12:56:01 +00:00
[.footer: https://www.drupal.org/core/gates#testing]
---
2018-06-15 06:43:54 +00:00
## _Testing in Drupal_
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
- _Drupal 7_ - SimpleTest (testing) module provided as part of core
2018-06-15 06:43:54 +00:00
- _Drupal 8_ - PHPUnit added as a core dependency
2019-02-05 01:27:13 +00:00
- _PHPUnit Initiative_ - SimpleTest to be deprecated and removed in Drupal 9
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
## Writing Tests (Drupal 8)
2018-06-15 06:43:54 +00:00
2019-02-05 01:27:13 +00:00
- PHP class with _.php_ extension
- _tests/src_ directory within each module
- Within the *Drupal\Tests\module_name* namespace
2018-06-15 06:43:54 +00:00
- Class name must match the filename
- Namespace must match the directory structure
- One test class per feature
2019-02-05 01:27:13 +00:00
- Each method must start with _test_
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
^ Different to D7
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
[.header: alignment(center)]
## _1._ Arrange
## _2._ Act
## _3._ Assert
2017-11-22 23:58:12 +00:00
---
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```php
// modules/example/tests/src/Functional/ExampleTest.php
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
namespace Drupal\Tests\example\Functional;
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
use Drupal\Tests\BrowserTestBase;
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
class ExampleTest extends BrowserTestBase {
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
public function testSomething() {
// Arrange
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
// Act
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
// Assert
}
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
}
```
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
^ PHP class
Filename matches class name
Namespace matches directory structure
Extend BrowserTestBase
Add test method
---
[.header: #53B0EB ]
## What to test?
- Creating nodes with data from an API
- Calculating attendance figures for an event
- Determining if an event is purchasble
- Promotions and coupons for new users
- Cloning events
- Queuing private message requests
- Emails for new memberships
- Closed support tickets are re-opened when comments are added
- Custom form validation rules
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
## What to test first?
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
- What is the core piece of functionality?
- What provides the most value to the client?
- What would you not like to be fixing on a Friday afternoon or after hours?
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
^ Payments! Anything related to money.
What would provide the largest negative impact to the client if it were to fail?
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
[.background-color: #FFFFFF ]
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
![inline 150% ](images/matt-stauffer-tweet.png )
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
## What to test first?
- Write a _new test_ when adding any _new functionality_
- Write a _regression test_ when _fixing a bug_
^ Use tests to replicate the bug
Could be a new test, or adding to an existing test
Test passes when the bug is fixed
That issue cannot be re-added without the test failing again
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
## Types of tests
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
- Unit
- Kernel _(integration)_
- Functional / FunctionalJavascript _(web, browser, feature)_
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
## Unit tests
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
- Tests PHP logic
- No database interaction
- Fast to run
- Need to mock dependencies
- Can become tightly coupled
- Can be hard to refactor
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
---
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
```php
// tests/src/Unit/JobTest.php
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
namespace Drupal\Tests\advancedqueue\Unit;
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
use Drupal\advancedqueue\Job;
use Drupal\Tests\UnitTestCase;
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
class JobTest extends UnitTestCase {
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
public function testCreate() {
$job = Job::create('test', ['my' => 'data']);
$this->assertEquals('test', $job->getType());
$this->assertEquals(['my' => 'data'], $job->getPayload());
$this->assertEquals(Job::STATE_QUEUED, $job->getState());
2018-06-15 06:43:54 +00:00
}
2019-02-05 01:27:13 +00:00
2018-06-15 06:43:54 +00:00
}
```
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
^ Within a Unit directory and namespace
Called JobTest because it's testing the Job class
Called testCreate because it's testing the create method
Create a job with the create method
Retrieve data from the object with getters
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
```php, [.highlight: 11]
// tests/src/Unit/JobTest.php
2017-11-22 23:58:12 +00:00
2019-02-05 01:27:13 +00:00
namespace Drupal\Tests\advancedqueue\Unit;
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
use Drupal\advancedqueue\Job;
use Drupal\Tests\UnitTestCase;
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
class JobTest extends UnitTestCase {
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
public function testCreate() {
$job = Job::create('test', ['my' => 'data']);
2017-11-22 23:58:12 +00:00
2019-02-05 01:27:13 +00:00
$this->assertEquals('test', $job->getType());
$this->assertEquals(['my' => 'data'], $job->getPayload());
$this->assertEquals(Job::STATE_QUEUED, $job->getState());
}
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
}
```
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
---
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
```php, [.highlight: 13-15]
// tests/src/Unit/JobTest.php
namespace Drupal\Tests\advancedqueue\Unit;
use Drupal\advancedqueue\Job;
use Drupal\Tests\UnitTestCase;
class JobTest extends UnitTestCase {
public function testCreate() {
$job = Job::create('test', ['my' => 'data']);
$this->assertEquals('test', $job->getType());
$this->assertEquals(['my' => 'data'], $job->getPayload());
$this->assertEquals(Job::STATE_QUEUED, $job->getState());
2017-10-21 12:56:01 +00:00
}
2019-02-05 01:27:13 +00:00
2017-10-21 12:56:01 +00:00
}
```
---
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
## Kernel Tests
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
- Integration tests
- Can install modules, interact with services, container, database
- Minimal Drupal bootstrap
- Faster than functional tests
- More setup required
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
---
2018-06-15 06:43:54 +00:00
2019-02-05 01:27:13 +00:00
```php
// tests/src/Kernel/ProcessorTest.php
2018-06-15 06:43:54 +00:00
2019-02-05 01:27:13 +00:00
namespace Drupal\Tests\advancedqueue\Kernel;
2018-06-15 06:43:54 +00:00
2019-02-05 01:27:13 +00:00
use Drupal\advancedqueue\Entity\Queue;
use Drupal\advancedqueue\Job;
use Drupal\KernelTests\KernelTestBase;
2018-06-15 06:43:54 +00:00
2019-02-05 01:27:13 +00:00
class ProcessorTest extends KernelTestBase {
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
...
2018-06-15 06:43:54 +00:00
2017-10-21 12:56:01 +00:00
}
```
---
2019-02-05 01:27:13 +00:00
```php
// tests/src/Kernel/ProcessorTest.php
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
protected function setUp() {
parent::setUp();
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
$this->installSchema('advancedqueue', ['advancedqueue']);
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
$this->queue = Queue::create([
'id' => 'test',
'label' => 'Test queue',
'backend' => 'database',
'backend_configuration' => [
'lease_time' => 5,
],
]);
$this->queue->save();
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
$this->processor = $this->container->get('advancedqueue.processor');
}
```
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
---
2017-11-22 23:58:12 +00:00
2019-02-05 01:27:13 +00:00
```php, [.highlight: 6]
// tests/src/Kernel/ProcessorTest.php
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
protected function setUp() {
parent::setUp();
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
$this->installSchema('advancedqueue', ['advancedqueue']);
$this->queue = Queue::create([
'id' => 'test',
'label' => 'Test queue',
'backend' => 'database',
'backend_configuration' => [
'lease_time' => 5,
],
]);
$this->queue->save();
$this->processor = $this->container->get('advancedqueue.processor');
2017-10-21 12:56:01 +00:00
}
```
---
2019-02-05 01:27:13 +00:00
```php, [.highlight: 8-16]
// tests/src/Kernel/ProcessorTest.php
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
protected function setUp() {
parent::setUp();
2017-11-22 23:58:12 +00:00
2019-02-05 01:27:13 +00:00
$this->installSchema('advancedqueue', ['advancedqueue']);
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
$this->queue = Queue::create([
'id' => 'test',
'label' => 'Test queue',
'backend' => 'database',
'backend_configuration' => [
'lease_time' => 5,
],
]);
$this->queue->save();
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
$this->processor = $this->container->get('advancedqueue.processor');
}
```
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
---
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
```php, [.highlight: 18]
// tests/src/Kernel/ProcessorTest.php
2018-06-15 06:43:54 +00:00
2019-02-05 01:27:13 +00:00
protected function setUp() {
parent::setUp();
2018-06-15 06:43:54 +00:00
2019-02-05 01:27:13 +00:00
$this->installSchema('advancedqueue', ['advancedqueue']);
$this->queue = Queue::create([
'id' => 'test',
'label' => 'Test queue',
'backend' => 'database',
'backend_configuration' => [
'lease_time' => 5,
],
]);
$this->queue->save();
$this->processor = $this->container->get('advancedqueue.processor');
2018-06-15 06:43:54 +00:00
}
2017-10-21 12:56:01 +00:00
```
---
2019-02-05 01:27:13 +00:00
```php
// tests/src/Kernel/ProcessorTest.php
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
public function testProcessor() {
$first_job = Job::create('simple', [
'test' => '1',
]);
2018-06-15 06:43:54 +00:00
2019-02-05 01:27:13 +00:00
$second_job = Job::create('flexible', [
'expected_state' => Job::STATE_SUCCESS,
'expected_message' => 'Done!',
]);
$third_job = Job::create(
'flexible', ['expected_exception' => 'DB down!'],
);
$fourth_job = Job::create('flexible', [
'expected_state' => Job::STATE_FAILURE,
'expected_message' => 'Failed!',
]);
...
}
```
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
```php, [.highlight: 6-10]
// tests/src/Kernel/ProcessorTest.php
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
public function testProcessor() {
...
$this->queue->enqueueJob($first_job);
$this->queue->enqueueJob($second_job);
$this->queue->enqueueJob($third_job);
$this->queue->enqueueJob($fourth_job);
$num_processed = $this->processor->processQueue($this->queue);
$this->assertEquals(4, $num_processed);
}
```
---
```php, [.highlight: 11-13]
// tests/src/Kernel/ProcessorTest.php
public function testProcessor() {
...
$this->queue->enqueueJob($first_job);
$this->queue->enqueueJob($second_job);
$this->queue->enqueueJob($third_job);
$this->queue->enqueueJob($fourth_job);
$num_processed = $this->processor->processQueue($this->queue);
$this->assertEquals(4, $num_processed);
}
```
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
## Functional Tests
- Tests end-to-end functionality
- UI testing
- Interacts with database
- Full Drupal installation
- Slower to run
- With/without JavaScript
^ testing profile
---
2018-06-15 06:43:54 +00:00
```php
2019-02-05 01:27:13 +00:00
// tests/src/Functional/QueueTest.php
2017-11-08 06:56:37 +00:00
2019-02-05 01:27:13 +00:00
namespace Drupal\Tests\advancedqueue\Functional;
2017-11-08 06:56:37 +00:00
2019-02-05 01:27:13 +00:00
use Drupal\advancedqueue\Entity\Queue;
use Drupal\advancedqueue\Entity\QueueInterface;
use Drupal\Tests\BrowserTestBase;
2017-11-08 06:56:37 +00:00
2019-02-05 01:27:13 +00:00
class QueueTest extends BrowserTestBase {
...
}
```
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
---
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
```php, [.highlight: 6-8]
// tests/src/Functional/QueueTest.php
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
protected function setUp() {
parent::setUp();
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
$this->placeBlock('local_tasks_block');
$this->placeBlock('local_actions_block');
$this->placeBlock('page_title_block');
2018-06-15 06:43:54 +00:00
2019-02-05 01:27:13 +00:00
$this->adminUser = $this->drupalCreateUser(['administer advancedqueue']);
$this->drupalLogin($this->adminUser);
2018-06-15 06:43:54 +00:00
}
```
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
```php, [.highlight: 10-11]
// tests/src/Functional/QueueTest.php
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
protected function setUp() {
parent::setUp();
$this->placeBlock('local_tasks_block');
$this->placeBlock('local_actions_block');
$this->placeBlock('page_title_block');
$this->adminUser = $this->drupalCreateUser(['administer advancedqueue']);
$this->drupalLogin($this->adminUser);
}
```
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
---
```php, [.highlight: 4-11]
// tests/src/Functional/QueueTest.php
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
public function testQueueDeletion() {
$queue = Queue::create([
'id' => 'test',
'label' => 'Test',
'backend' => 'database',
'processor' => QueueInterface::PROCESSOR_DAEMON,
'processing_time' => 100,
]);
$queue->save();
$this->drupalGet('admin/config/system/queues/manage/' . $queue->id() . '/delete');
$this->submitForm([], 'Delete');
$this->assertSession()->addressEquals('admin/config/system/queues');
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
$queue_exists = (bool) Queue::load('test');
$this->assertEmpty($queue_exists, 'The queue has been deleted from the database.');
}
2018-06-15 06:43:54 +00:00
```
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
```php, [.highlight: 12-14]
// tests/src/Functional/QueueTest.php
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
public function testQueueDeletion() {
$queue = Queue::create([
'id' => 'test',
'label' => 'Test',
'backend' => 'database',
'processor' => QueueInterface::PROCESSOR_DAEMON,
'processing_time' => 100,
]);
$queue->save();
$this->drupalGet('admin/config/system/queues/manage/' . $queue->id() . '/delete');
$this->submitForm([], 'Delete');
$this->assertSession()->addressEquals('admin/config/system/queues');
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
$queue_exists = (bool) Queue::load('test');
$this->assertEmpty($queue_exists, 'The queue has been deleted from the database.');
}
```
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
---
```php, [.highlight: 16-17]
// tests/src/Functional/QueueTest.php
public function testQueueDeletion() {
$queue = Queue::create([
'id' => 'test',
'label' => 'Test',
'backend' => 'database',
'processor' => QueueInterface::PROCESSOR_DAEMON,
'processing_time' => 100,
]);
$queue->save();
$this->drupalGet('admin/config/system/queues/manage/' . $queue->id() . '/delete');
$this->submitForm([], 'Delete');
$this->assertSession()->addressEquals('admin/config/system/queues');
$queue_exists = (bool) Queue::load('test');
$this->assertEmpty($queue_exists, 'The queue has been deleted from the database.');
2018-06-15 06:43:54 +00:00
}
2017-10-21 12:56:01 +00:00
```
---
2018-06-15 06:43:54 +00:00
[.header: #FFFFFF , alignment(left)]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
### _How do I know_
## Which type of test to use?
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
---
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
### _Need a browser?_
## Use a functional test
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
---
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
### _Interact with other services?_
## Use a kernel test
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
### _Isolated PHP code?_
## Use a unit test
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
---
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
## _Should you test that_ <br>a block is rendered correctly?
---
## _Or should you test_ <br>your render array to generate the block?
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
^ The answer might be 'both'.
The right type of test to use might not be that obvious.
You may be able to use a different type of test if you take a different approach.
---
[.header: #53B0EB ]
## Setup (functional)
2017-11-22 23:58:12 +00:00
2017-10-21 12:56:01 +00:00
```
2018-06-15 06:43:54 +00:00
drupalCreateUser()
drupalCreateRole()
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
drupalLogin()
drupalLogout()
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
drupalGet()
drupalPost()
drupalPostForm()
```
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
## _Setup (kernel)_
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```php
# UserCreationTrait
createUser()
createAdminRole()
createRole()
checkPermissions()
# CommentTestTrait
addDefaultCommentField()
# AssertMailTrait
getMails()
assertMail()
```
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
2017-11-22 23:58:12 +00:00
2019-02-05 01:27:13 +00:00
## Assertions
2017-10-21 12:56:01 +00:00
```php
2018-06-15 06:43:54 +00:00
assertTrue()
assertFalse()
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
assertEquals()
2019-02-05 01:27:13 +00:00
assertSame()
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
assertNull()
assertNotNull()
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
assertCount()
assertEmpty()
assertArraySubset()
2017-10-21 12:56:01 +00:00
```
---
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
2017-11-22 23:58:12 +00:00
2019-02-05 01:27:13 +00:00
## Assertions (functional)
2017-10-21 12:56:01 +00:00
```php
2019-02-05 01:27:13 +00:00
assertSession()
2018-06-15 06:43:54 +00:00
pageTextContains()
pageTextNotContains()
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
linkByHrefExists()
linkByHrefNotExists()
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
statusCodeEquals()
statusCodeNotEquals()
2017-10-21 12:56:01 +00:00
```
---
2018-06-15 06:43:54 +00:00
[.header: alignment(center)]
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
# _Real life_ example
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
---
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
[.background-color: #FFFFFF ]
[.footer-style: #2F2F2F ]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
![inline 150% ](images/broadbean.png )
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
---
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
## Specification
2018-06-15 06:43:54 +00:00
2019-02-05 01:27:13 +00:00
- Job adverts created in Broadbean UI, needs to create nodes in Drupal
- Application URL links users to separate application system
- Jobs need to be linked to offices
- Job length specified in number of days
2018-06-15 06:43:54 +00:00
- Path is specified as a field in the API
- Application URL constructed from domain, includes role ID as a GET parameter and optionally UTM parameters
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
[.background-color: #FFFFFF ]
![inline 125% ](images/broadbean-drupal-flow-1.png )
---
[.background-color: #FFFFFF ]
![inline 125% ](images/broadbean-drupal-flow-2.png )
---
2017-10-21 12:56:01 +00:00
```php
2018-06-15 06:43:54 +00:00
$data = [
'command' => 'add',
'username' => 'bobsmith',
'password' => 'p455w0rd',
'active_for' => '365',
'application_email' => 'bob.12345.123@smith.aplitrak.com',
'branch_address' => '123 Fake St, Bristol, BS1 2AB',
'branch_name' => 'Test',
'contract' => 'Temporary',
'details' => 'This is the detailed description.',
'job_id' => 'abc123_1234567',
'job_title' => 'Healthcare Assistant (HCA)',
'job_type' => 'Care at Home',
'keywords' => 'flexible, Bristol, part-time',
'locations' => 'Bath, Devizes',
'role_id' => 'A/52/86',
'salary' => '32,000.00 per annum',
'salary_prefix' => 'Basic Salary',
'status' => 'Part time',
'summary' => 'This is the short description.',
'url_alias' => 'healthcare-assistant-aldershot-june17',
];
2017-10-21 12:56:01 +00:00
```
2017-10-05 06:53:55 +00:00
---
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
## Implementation
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
- Added route to accept data from API as XML
2019-02-05 01:27:13 +00:00
- Added system user with API role to authenticate
- *active_for* converted from number of days to UNIX timestamp
- *branch_name* and *locations* converted from plain text to entity reference (job node to office node)
- *url_alias* property mapped to *path*
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
## Implementation
- If no error, create the job node, return OK response to Broadbean
- If an Exception is thrown, return an error code and message
^ Required field missing
Incorrect branch name
---
[.header: #53B0EB ]
## Testing Goals
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
- Ensure job nodes are _successfully created_
- Ensure that fields are _mapped correctly_
- Ensure that _calculations are correct_
- Ensure that entity references are _linked correctly_
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
## Types of tests
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
- _Unit:_ ensure number of days are converted to timestamps correctly
- _Kernel:_ job nodes can be added and deleted, expired job nodes are deleted, application URL is generated correctly
- _Functional:_ job nodes are created with the correct URL and the correct response code is returned
- _FunctionalJavaScript:_ application URL is updated with JavaScript based on UTM parameters (hosting)
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
## Results
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
- _0 bugs!_
- Reduced debugging time
- Easier to identify where issues occurred and responsibilities
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
[.header: alignment(center)]
## Running Tests
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
### _Option 1_
## SimpleTest module (UI)
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
![fit ](images/d8-simpletest-1.png )
2017-10-05 06:53:55 +00:00
---
2019-02-05 01:27:13 +00:00
![fit ](images/d8-simpletest-2.png )
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
---
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
![fit ](images/d8-simpletest-3.png )
---
![fit ](images/d8-simpletest-4.png )
---
![fit ](images/d8-simpletest-5.png )
---
![fit ](images/d8-simpletest-6.png )
---
![fit ](images/d8-simpletest-7.png )
---
### _Option 2_
## Core script
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
```
$ php core/scripts/run-tests.sh
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
$ php core/scripts/run-tests.sh --module example
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
$ php core/scripts/run-tests.sh --class ExampleTest
```
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
---
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
### _Option 3_
## PHPUnit
---
## Prerequisite _(creating a phpunit.xml file)_
- Configures PHPUnit
- Needed to run some types of tests
- Ignored by Git by default
- Copy _core/phpunit.xml.dist_ to _core/phpunit.xml_
- Add and change as needed
- `SIMPLETEST_BASE_URL` , `SIMPLETEST_DB` , `BROWSERTEST_OUTPUT_DIRECTORY`
- `stopOnFailure="true"`
---
```
cd web
../vendor/bin/phpunit -c core \
modules/contrib/examples/phpunit_example
```
---
```
cd web/core
../../vendor/bin/phpunit \
../modules/contrib/examples/phpunit_example
```
---
2018-06-15 06:43:54 +00:00
```
2019-02-05 01:27:13 +00:00
--filter
--testsuite
--group
2018-06-15 06:43:54 +00:00
2019-02-05 01:27:13 +00:00
--colors
2018-06-15 06:43:54 +00:00
2019-02-05 01:27:13 +00:00
--stop-on-failure
--verbose --debug
2017-10-21 12:56:01 +00:00
```
---
2019-02-05 01:27:13 +00:00
![fit ](images/phpstorm-integration.png )
---
2018-06-15 06:43:54 +00:00
[.header: alignment(center)]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
## _Test Driven_<br> Development
2017-10-05 06:53:55 +00:00
---
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
## Test Driven Development
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
- Write a test
2019-02-05 01:27:13 +00:00
- Test fails
- Write code
- Test passes
- Refactor
2018-06-15 06:43:54 +00:00
- Repeat
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
---
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
[.background-color: #FFFFFF ]
[.footer: https://github.com/foundersandcoders/testing-tdd-intro]
[.footer-style: #2F2F2F ]
![100% ](images/tdd-loop.png )
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
[.header: alignment(center)]
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
## Red, Green, Refactor
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
---
2017-11-22 23:58:12 +00:00
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
## Porting Modules to Drupal 8
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
- Make a new branch
- Add/update the tests
- Write code to make the tests pass
- Refactor
- Repeat
2017-11-22 23:58:12 +00:00
---
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
## How I Write Tests - "Outside In"
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
- Start with functional tests
- Drop down to integration or unit tests where needed
- Programming by wishful thinking
- Write comments first, then fill in the code
2019-02-05 01:27:13 +00:00
- Sometimes write assertions first
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
---
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
[.header: alignment(center)]
2017-11-22 23:58:12 +00:00
2019-02-05 01:27:13 +00:00
## [fit] _Building a new Drupal 8 Module with_
## [fit] test driven development
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
## Acceptance criteria
2018-06-15 06:43:54 +00:00
- As a site visitor
- I want to see a list of published articles at /blog
- Ordered by post date
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
## Tasks
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
- Ensure the blog page exists
- Ensure only published articles are shown
- Ensure the articles are shown in the correct order
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
---
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
[.header: #53B0EB ]
## Implementation
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
- Use views module
- Do the mininum amount at each step, make no assumptions, let the tests guide us
- Start with functional test
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
### _Step 1_
## Create the module
---
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```yml
# tdd_blog.info.yml
2019-02-05 01:27:13 +00:00
name: 'TDD Blog'
2018-06-15 06:43:54 +00:00
core: '8.x'
type: 'module'
2017-10-21 12:56:01 +00:00
```
---
2019-02-05 01:27:13 +00:00
### _Step 2_
2018-06-15 06:43:54 +00:00
## Ensure the blog page exists
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
---
```php
// tests/src/Functional/BlogPageTest.php
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
namespace Drupal\Tests\tdd_blog\Functional;
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
use Drupal\Tests\BrowserTestBase;
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
class BlogPageTest extends BrowserTestBase {
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
protected static $modules = ['tdd_blog'];
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
public function testBlogPageExists() {
$this->drupalGet('/blog');
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
$this->assertSession()->statusCodeEquals(200);
}
2017-10-21 12:56:01 +00:00
}
```
---
2019-02-05 01:27:13 +00:00
```php, [.highlight: 3]
2018-06-15 06:43:54 +00:00
// tests/src/Functional/BlogPageTest.php
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
namespace Drupal\Tests\tdd_blog\Functional;
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
use Drupal\Tests\BrowserTestBase;
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
class BlogPageTest extends BrowserTestBase {
protected static $modules = ['tdd_blog'];
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
public function testBlogPageExists() {
$this->drupalGet('/blog');
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
$this->assertSession()->statusCodeEquals(200);
}
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
}
```
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
```php, [.highlight: 5-7]
2018-06-15 06:43:54 +00:00
// tests/src/Functional/BlogPageTest.php
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
namespace Drupal\Tests\tdd_blog\Functional;
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
use Drupal\Tests\BrowserTestBase;
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
class BlogPageTest extends BrowserTestBase {
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
protected static $modules = ['tdd_blog'];
public function testBlogPageExists() {
$this->drupalGet('/blog');
2017-10-21 12:56:01 +00:00
$this->assertSession()->statusCodeEquals(200);
}
2018-06-15 06:43:54 +00:00
2017-10-21 12:56:01 +00:00
}
```
---
2019-02-05 01:27:13 +00:00
```php, [.highlight: 9]
2018-06-15 06:43:54 +00:00
// tests/src/Functional/BlogPageTest.php
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
namespace Drupal\Tests\tdd_blog\Functional;
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
use Drupal\Tests\BrowserTestBase;
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
class BlogPageTest extends BrowserTestBase {
protected static $modules = ['tdd_blog'];
public function testBlogPageExists() {
$this->drupalGet('/blog');
$this->assertSession()->statusCodeEquals(200);
}
}
```
---
2019-02-05 01:27:13 +00:00
```php, [.highlight: 11-15]
2018-06-15 06:43:54 +00:00
// tests/src/Functional/BlogPageTest.php
namespace Drupal\Tests\tdd_blog\Functional;
use Drupal\Tests\BrowserTestBase;
class BlogPageTest extends BrowserTestBase {
protected static $modules = ['tdd_blog'];
public function testBlogPageExists() {
$this->drupalGet('/blog');
$this->assertSession()->statusCodeEquals(200);
}
}
```
---
```bash, [.highlight: 1]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
Testing modules/custom/tdd_blog
E 1 / 1 (100%)
Time: 19.31 seconds, Memory: 6.00MB
There was 1 error:
1) Drupal\Tests\tdd_blog\Functional\BlogPageTest::testBlogPageExists
Behat\Mink\Exception\ExpectationException: Current response status code is 404, but 200 expected.
/var/www/vendor/behat/mink/src/WebAssert.php:768
/var/www/vendor/behat/mink/src/WebAssert.php:130
/var/www/web/modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php:13
ERRORS!
Tests: 1, Assertions: 3, Errors: 1.
```
---
```bash, [.highlight: 4]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
Testing modules/custom/tdd_blog
E 1 / 1 (100%)
Time: 19.31 seconds, Memory: 6.00MB
There was 1 error:
1) Drupal\Tests\tdd_blog\Functional\BlogPageTest::testBlogPageExists
Behat\Mink\Exception\ExpectationException: Current response status code is 404, but 200 expected.
/var/www/vendor/behat/mink/src/WebAssert.php:768
2017-10-21 12:56:01 +00:00
/var/www/vendor/behat/mink/src/WebAssert.php:130
2018-06-15 06:43:54 +00:00
/var/www/web/modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php:13
ERRORS!
Tests: 1, Assertions: 3, Errors: 1.
2017-10-21 12:56:01 +00:00
```
---
2018-06-15 06:43:54 +00:00
```bash, [.highlight: 5-13]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
Testing modules/custom/tdd_blog
E 1 / 1 (100%)
Time: 19.31 seconds, Memory: 6.00MB
There was 1 error:
1) Drupal\Tests\tdd_blog\Functional\BlogPageTest::testBlogPageExists
Behat\Mink\Exception\ExpectationException: Current response status code is 404, but 200 expected.
/var/www/vendor/behat/mink/src/WebAssert.php:768
/var/www/vendor/behat/mink/src/WebAssert.php:130
/var/www/web/modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php:13
ERRORS!
Tests: 1, Assertions: 3, Errors: 1.
```
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
```bash, [.highlight: 14-16]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
Testing modules/custom/tdd_blog
E 1 / 1 (100%)
Time: 19.31 seconds, Memory: 6.00MB
There was 1 error:
1) Drupal\Tests\tdd_blog\Functional\BlogPageTest::testBlogPageExists
Behat\Mink\Exception\ExpectationException: Current response status code is 404, but 200 expected.
/var/www/vendor/behat/mink/src/WebAssert.php:768
/var/www/vendor/behat/mink/src/WebAssert.php:130
/var/www/web/modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php:13
ERRORS!
Tests: 1, Assertions: 3, Errors: 1.
2017-10-21 12:56:01 +00:00
```
2018-06-15 06:43:54 +00:00
---
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```bash, [.highlight: 18-19]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
Testing modules/custom/tdd_blog
E 1 / 1 (100%)
Time: 19.31 seconds, Memory: 6.00MB
2017-10-21 12:56:01 +00:00
There was 1 error:
2018-06-15 06:43:54 +00:00
1) Drupal\Tests\tdd_blog\Functional\BlogPageTest::testBlogPageExists
Behat\Mink\Exception\ExpectationException: Current response status code is 404, but 200 expected.
/var/www/vendor/behat/mink/src/WebAssert.php:768
/var/www/vendor/behat/mink/src/WebAssert.php:130
/var/www/web/modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php:13
ERRORS!
Tests: 1, Assertions: 3, Errors: 1.
2017-10-21 12:56:01 +00:00
```
---
2018-06-15 06:43:54 +00:00
- _The view has not been created_
2019-02-05 01:27:13 +00:00
- Create a new view, page display
2018-06-15 06:43:54 +00:00
- Set the path
- Export the config
- Copy it into the module's `config/install` directory
---
2019-02-05 01:27:13 +00:00
![fit ](images/tdd-blog-1.png )
---
![fit ](images/tdd-blog-2.png )
---
```
drush cex -y
cp ../config/default/views.view.blog.yml \
modules/custom/tdd_blog/config/install
```
---
```diff
# views.view.blog.yml
- uuid: 84305edf-7aef-4109-bc93-e87f685fb678
langcode: en
status: true
dependencies:
config:
- node.type.article
module:
- node
- user
- _core:
- default_config_hash: iGZkqLWpwWNORq6_fy6v_Kn_KE4BjYHqj9vpgQsWJCs
id: blog
...
```
---
2018-06-15 06:43:54 +00:00
```[.highlight: 11-13]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
Testing modules/custom/tdd_blog
E 1 / 1 (100%)
Time: 16.02 seconds, Memory: 6.00MB
There was 1 error:
1) Drupal\Tests\tdd_blog\Functional\BlogPageTest::testBlogPageExists
Drupal\Core\Config\UnmetDependenciesException: Configuration objects provided by < em class = "placeholder" > tdd_blog</ em >
have unmet dependencies: < em class = "placeholder" > views.view.blog (node.type.article, node, views)< / em >
/var/www/web/core/lib/Drupal/Core/Config/UnmetDependenciesException.php:98
/var/www/web/core/lib/Drupal/Core/Config/ConfigInstaller.php:469
/var/www/web/core/lib/Drupal/Core/ProxyClass/Config/ConfigInstaller.php:132
/var/www/web/core/lib/Drupal/Core/Extension/ModuleInstaller.php:145
/var/www/web/core/lib/Drupal/Core/ProxyClass/Extension/ModuleInstaller.php:83
/var/www/web/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php:437
/var/www/web/core/tests/Drupal/Tests/BrowserTestBase.php:1055
/var/www/web/core/tests/Drupal/Tests/BrowserTestBase.php:490
ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
```
---
```yml,[.highlight: 1, 7-10]
# tdd_blog.info.yml
2019-02-05 01:27:13 +00:00
name: 'TDD Blog'
2018-06-15 06:43:54 +00:00
description: 'A demo module to show test driven module development.'
2017-10-21 12:56:01 +00:00
core: 8.x
type: module
dependencies:
2018-06-15 06:43:54 +00:00
- 'drupal:node'
- 'drupal:views'
2017-10-21 12:56:01 +00:00
```
---
2018-06-15 06:43:54 +00:00
```[.highlight: 10-13]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
Testing modules/custom/tdd_blog
E 1 / 1 (100%)
Time: 20 seconds, Memory: 6.00MB
There was 1 error:
1) Drupal\Tests\tdd_blog\Functional\BlogPageTest::testBlogPageExists
Drupal\Core\Config\UnmetDependenciesException: Configuration objects provided by < em class = "placeholder" > tdd_blog</ em >
have unmet dependencies: < em class = "placeholder" > views.view.blog (node.type.article)< / em >
/var/www/web/core/lib/Drupal/Core/Config/UnmetDependenciesException.php:98
/var/www/web/core/lib/Drupal/Core/Config/ConfigInstaller.php:469
/var/www/web/core/lib/Drupal/Core/ProxyClass/Config/ConfigInstaller.php:132
/var/www/web/core/lib/Drupal/Core/Extension/ModuleInstaller.php:145
/var/www/web/core/lib/Drupal/Core/ProxyClass/Extension/ModuleInstaller.php:83
/var/www/web/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php:437
/var/www/web/core/tests/Drupal/Tests/BrowserTestBase.php:1055
/var/www/web/core/tests/Drupal/Tests/BrowserTestBase.php:490
ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
2017-10-21 12:56:01 +00:00
```
2018-06-15 06:43:54 +00:00
---
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
- Add the article content type
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
---
```[.highlight: 5, 9]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
Testing modules/custom/tdd_blog
. 1 / 1 (100%)
Time: 23.36 seconds, Memory: 6.00MB
OK (1 test, 3 assertions)
2017-10-21 12:56:01 +00:00
```
---
2019-02-05 01:27:13 +00:00
[.build-lists: false]
2018-06-15 06:43:54 +00:00
## _Tasks_
- ~~Ensure the blog page exists~~
- Ensure only published articles are shown
- Ensure the articles are shown in the correct order
---
2019-02-05 01:27:13 +00:00
### _Step 3_
2018-06-15 06:43:54 +00:00
## Ensure only published articles are shown
---
2017-10-21 12:56:01 +00:00
```php
2018-06-15 06:43:54 +00:00
public function testOnlyPublishedArticlesAreShown() {
// Given I have a mixture of published and unpublished articles,
2017-10-21 12:56:01 +00:00
// as well as other types of content.
2018-06-15 06:43:54 +00:00
// When I view the blog page.
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
// I should only see the published articles.
2017-10-21 12:56:01 +00:00
}
```
---
2019-02-05 01:27:13 +00:00
### _Option 1_
## Functional tests
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
---
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```php,[.highlight: 1, 4-8]
// modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php
public function testOnlyPublishedArticlesAreShown() {
// Given I have a mixture of published and unpublished articles,
// as well as other types of content.
$node1 = $this->drupalCreateNode(['type' => 'page', 'status' => 1]);
$node2 = $this->drupalCreateNode(['type' => 'article', 'status' => 1]);
$node3 = $this->drupalCreateNode(['type' => 'article', 'status' => 0]);
// When I view the blog page.
$this->drupalGet('/blog');
// I should only see the published articles.
$assert = $this->assertSession();
$assert->pageTextContains($node2->label());
$assert->pageTextNotContains($node1->label());
$assert->pageTextNotContains($node3->label());
2017-10-21 12:56:01 +00:00
}
```
2018-06-15 06:43:54 +00:00
^ Different ways to achieve this. This is taking the functional test approach.
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
```php,[.highlight: 10-12]
// modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php
public function testOnlyPublishedArticlesAreShown() {
// Given I have a mixture of published and unpublished articles,
// as well as other types of content.
$node1 = $this->drupalCreateNode(['type' => 'page', 'status' => 1]);
$node2 = $this->drupalCreateNode(['type' => 'article', 'status' => 1]);
$node3 = $this->drupalCreateNode(['type' => 'article', 'status' => 0]);
// When I view the blog page.
$this->drupalGet('/blog');
// I should only see the published articles.
$assert = $this->assertSession();
$assert->pageTextContains($node2->label());
$assert->pageTextNotContains($node1->label());
$assert->pageTextNotContains($node3->label());
}
```
2017-11-08 06:56:37 +00:00
2018-06-15 06:43:54 +00:00
---
2017-11-22 23:58:12 +00:00
2017-11-08 06:56:37 +00:00
2018-06-15 06:43:54 +00:00
```php, [.highlight: 13-17]
// modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php
2017-11-08 06:56:37 +00:00
2018-06-15 06:43:54 +00:00
public function testOnlyPublishedArticlesAreShown() {
// Given I have a mixture of published and unpublished articles,
// as well as other types of content.
$node1 = $this->drupalCreateNode(['type' => 'page', 'status' => 1]);
$node2 = $this->drupalCreateNode(['type' => 'article', 'status' => 1]);
$node3 = $this->drupalCreateNode(['type' => 'article', 'status' => 0]);
// When I view the blog page.
$this->drupalGet('/blog');
// I should only see the published articles.
$assert = $this->assertSession();
$assert->pageTextContains($node2->label());
$assert->pageTextNotContains($node1->label());
$assert->pageTextNotContains($node3->label());
2017-11-08 06:56:37 +00:00
}
```
---
2019-02-05 01:27:13 +00:00
### _Option 2_
## Kernel tests
2018-06-15 06:43:54 +00:00
---
2017-10-21 12:56:01 +00:00
```php
2018-06-15 06:43:54 +00:00
namespace Drupal\Tests\tdd_blog\Kernel;
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\Tests\node\Traits\NodeCreationTrait;
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
class BlogPageTest extends EntityKernelTestBase {
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
use NodeCreationTrait;
public static $modules = ['node'];
public function testOnlyPublishedArticlesAreShown() {
$this->createNode(['type' => 'page', 'status' => 1]);
$this->createNode(['type' => 'article', 'status' => 1]);
$this->createNode(['type' => 'article', 'status' => 0]);
}
2017-10-21 12:56:01 +00:00
}
```
2018-06-15 06:43:54 +00:00
^ Kernel test approach
Dropping down a level
No need for the brower, not asserting against HTML
Faster to run
2017-10-21 12:56:01 +00:00
---
2019-02-05 01:27:13 +00:00
```php, [.highlight: 1-6]
2018-06-15 06:43:54 +00:00
namespace Drupal\Tests\tdd_blog\Kernel;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\Tests\node\Traits\NodeCreationTrait;
class BlogPageTest extends EntityKernelTestBase {
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
use NodeCreationTrait;
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
public static $modules = ['node'];
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
public function testOnlyPublishedArticlesAreShown() {
$this->createNode(['type' => 'page', 'status' => 1]);
$this->createNode(['type' => 'article', 'status' => 1]);
$this->createNode(['type' => 'article', 'status' => 0]);
}
2017-10-21 12:56:01 +00:00
}
```
---
2019-02-05 01:27:13 +00:00
```php, [.highlight: 8]
2018-06-15 06:43:54 +00:00
namespace Drupal\Tests\tdd_blog\Kernel;
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\Tests\node\Traits\NodeCreationTrait;
class BlogPageTest extends EntityKernelTestBase {
use NodeCreationTrait;
public static $modules = ['node'];
public function testOnlyPublishedArticlesAreShown() {
$this->createNode(['type' => 'page', 'status' => 1]);
$this->createNode(['type' => 'article', 'status' => 1]);
$this->createNode(['type' => 'article', 'status' => 0]);
}
}
2017-10-21 12:56:01 +00:00
```
---
2019-02-05 01:27:13 +00:00
```php, [.highlight: 12-16]
2018-06-15 06:43:54 +00:00
namespace Drupal\Tests\tdd_blog\Kernel;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\Tests\node\Traits\NodeCreationTrait;
class BlogPageTest extends EntityKernelTestBase {
use NodeCreationTrait;
public static $modules = ['node'];
public function testOnlyPublishedArticlesAreShown() {
$this->createNode(['type' => 'page', 'status' => 1]);
$this->createNode(['type' => 'article', 'status' => 1]);
$this->createNode(['type' => 'article', 'status' => 0]);
}
}
2017-10-21 12:56:01 +00:00
```
---
2018-06-15 06:43:54 +00:00
```[.highlight: 9-16]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog/tests/src/Kernel/
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
Testing modules/custom/tdd_blog/tests/src/Kernel/
E 1 / 1 (100%)
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
Time: 6.22 seconds, Memory: 6.00MB
There was 1 error:
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
1) Drupal\Tests\tdd_blog\Kernel\BlogPageTest::testOnlyPublishedArticlesAreShown
Error: Call to a member function id() on boolean
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
/var/www/web/core/modules/filter/filter.module:212
/var/www/web/core/modules/node/tests/src/Traits/NodeCreationTrait.php:73
/var/www/web/modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php:13
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
ERRORS!
Tests: 1, Assertions: 2, Errors: 1.
2017-10-21 12:56:01 +00:00
```
---
2018-06-15 06:43:54 +00:00
```php, [.highlight: 2]
public function testOnlyPublishedArticlesAreShown() {
$this->installConfig(['filter']);
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
$this->createNode(['type' => 'page', 'status' => 1]);
$this->createNode(['type' => 'article', 'status' => 1]);
$this->createNode(['type' => 'article', 'status' => 0]);
2017-10-21 12:56:01 +00:00
}
```
---
2018-06-15 06:43:54 +00:00
```php, [.highlight: 8]
public function testOnlyPublishedArticlesAreShown() {
$this->installConfig(['filter']);
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
$this->createNode(['type' => 'page', 'status' => 1]);
$this->createNode(['type' => 'article', 'status' => 1]);
$this->createNode(['type' => 'article', 'status' => 0]);
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
$results = views_get_view_result('blog');
2017-10-21 12:56:01 +00:00
}
```
2017-10-05 06:53:55 +00:00
---
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```php, [.highlight: 3]
...
2017-10-05 06:53:55 +00:00
2018-06-15 06:43:54 +00:00
public static $modules = ['node', 'tdd_blog', 'views'];
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
public function testOnlyPublishedArticlesAreShown() {
$this->installConfig(['filter', 'tdd_blog']);
$this->createNode(['type' => 'page', 'status' => 1]);
$this->createNode(['type' => 'article', 'status' => 1]);
$this->createNode(['type' => 'article', 'status' => 0]);
$results = views_get_view_result('blog');
$this->assertCount(1, $results);
$this->assertEquals(2, $results[0]->_entity->id());
}
2017-10-21 12:56:01 +00:00
```
2017-10-05 06:53:55 +00:00
---
2018-06-15 06:43:54 +00:00
```php, [.highlight: 6]
...
public static $modules = ['node', 'tdd_blog', 'views'];
public function testOnlyPublishedArticlesAreShown() {
$this->installConfig(['filter', 'tdd_blog']);
$this->createNode(['type' => 'page', 'status' => 1]);
$this->createNode(['type' => 'article', 'status' => 1]);
$this->createNode(['type' => 'article', 'status' => 0]);
2017-10-05 06:53:55 +00:00
2018-06-15 06:43:54 +00:00
$results = views_get_view_result('blog');
$this->assertCount(1, $results);
$this->assertEquals(2, $results[0]->_entity->id());
}
2017-10-21 12:56:01 +00:00
```
2017-10-05 06:53:55 +00:00
---
2018-06-15 06:43:54 +00:00
```php, [.highlight: 8-15]
...
public static $modules = ['node', 'tdd_blog', 'views'];
public function testOnlyPublishedArticlesAreShown() {
$this->installConfig(['filter', 'tdd_blog']);
$this->createNode(['type' => 'page', 'status' => 1]);
$this->createNode(['type' => 'article', 'status' => 1]);
$this->createNode(['type' => 'article', 'status' => 0]);
$results = views_get_view_result('blog');
$this->assertCount(1, $results);
$this->assertEquals(2, $results[0]->_entity->id());
}
```
^ Assert
Should only be one result, should be node 2
Node IDs are reset on each test method
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
2017-10-21 12:56:01 +00:00
```
2018-06-15 06:43:54 +00:00
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
Testing web/modules/custom/tdd_blog/tests/src/Kernel
F 1 / 1 (100%)
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
Time: 2.16 seconds, Memory: 6.00MB
There was 1 failure:
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
1) Drupal\Tests\tdd_blog\Kernel\BlogPageTest::testOnlyPublishedArticlesAreShown
2019-02-05 01:27:13 +00:00
Failed asserting that actual size 2 matches expected size 1.
2018-06-15 06:43:54 +00:00
/Users/opdavies/Code/drupal-testing-workshop/web/modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php:23
FAILURES!
Tests: 1, Assertions: 4, Failures: 1.
2017-10-21 12:56:01 +00:00
```
---
2018-06-15 06:43:54 +00:00
```[.highlight: 8-13]
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
Testing web/modules/custom/tdd_blog/tests/src/Kernel
F 1 / 1 (100%)
Time: 2.16 seconds, Memory: 6.00MB
There was 1 failure:
1) Drupal\Tests\tdd_blog\Kernel\BlogPageTest::testOnlyPublishedArticlesAreShown
2019-02-05 01:27:13 +00:00
Failed asserting that actual size 2 matches expected size 1.
2018-06-15 06:43:54 +00:00
/Users/opdavies/Code/drupal-testing-workshop/web/modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php:23
FAILURES!
Tests: 1, Assertions: 4, Failures: 1.
2017-10-21 12:56:01 +00:00
```
2018-06-15 06:43:54 +00:00
---
2017-10-21 12:56:01 +00:00
2019-02-05 01:27:13 +00:00
![inline ](images/tdd-blog-3.png )
---
>- _There is no content type filter on the view_
- Add the filter
- Re-export and save the view
---
![inline ](images/tdd-blog-4.png )
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
---
```[.highlight: 3-8]
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
Testing web/modules/custom/tdd_blog/tests/src/Kernel
. 1 / 1 (100%)
Time: 2.02 seconds, Memory: 6.00MB
OK (1 test, 6 assertions)
2017-10-21 12:56:01 +00:00
```
---
2019-02-05 01:27:13 +00:00
[.build-lists: false]
2018-06-15 06:43:54 +00:00
## _Tasks_
- ~~Ensure the blog page exists~~
- ~~Ensure only published articles are shown~~
- Ensure the articles are shown in the correct order
---
2019-02-05 01:27:13 +00:00
### _Step 4_
## Ensure the articles are ordered by date
2017-11-22 23:58:12 +00:00
---
2018-06-15 06:43:54 +00:00
2017-11-22 23:58:12 +00:00
```php
2018-06-15 06:43:54 +00:00
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
public function testArticlesAreOrderedByDate() {
// Given that I have numerous articles with different post dates.
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
// When I go to the blog page.
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
// The articles are ordered by post date.
2017-11-22 23:58:12 +00:00
}
```
---
2018-06-15 06:43:54 +00:00
```php, [.highlight: 4-9]
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
public function testArticlesAreOrderedByDate() {
// Given that I have numerous articles with different post dates.
2019-02-05 01:27:13 +00:00
$this->createNode(['type' => 'article', 'created' => (new \DateTime('+1 day'))->getTimestamp()]);
$this->createNode(['type' => 'article', 'created' => (new \DateTime('+1 month'))->getTimestamp()]);
$this->createNode(['type' => 'article', 'created' => (new \DateTime('+3 days'))->getTimestamp()]);
$this->createNode(['type' => 'article', 'created' => (new \DateTime('+1 hour'))->getTimestamp()]);
2018-06-15 06:43:54 +00:00
// When I go to the blog page.
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
// The articles are ordered by post date.
2017-11-22 23:58:12 +00:00
}
```
---
2019-02-05 01:27:13 +00:00
```php
$this->createNode([
'type' => 'article',
'created' => (new \DateTime())->modify('+1 day')->getTimestamp(),
]);
```
^ Array of default values
---
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
```php, [.highlight: 10-11]
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
public function testArticlesAreOrderedByDate() {
// Given that I have numerous articles with different post dates.
$this->createNode(['type' => 'article', 'created' => (new \DateTime())->modify('+1 day')->getTimestamp()]);
$this->createNode(['type' => 'article', 'created' => (new \DateTime())->modify('+1 month')->getTimestamp()]);
$this->createNode(['type' => 'article', 'created' => (new \DateTime())->modify('+3 days')->getTimestamp()]);
$this->createNode(['type' => 'article', 'created' => (new \DateTime())->modify('+1 hour')->getTimestamp()]);
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
// When I go to the blog page.
$results = views_get_view_result('blog');
// The articles are ordered by post date.
2017-11-22 23:58:12 +00:00
}
```
---
2018-06-15 06:43:54 +00:00
```php, [.highlight:10-15]
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
public function testArticlesAreOrderedByDate() {
// Given that I have numerous articles with different post dates.
$this->createNode(['type' => 'article', 'created' => (new \DateTime())->modify('+1 day')->getTimestamp()]);
$this->createNode(['type' => 'article', 'created' => (new \DateTime())->modify('+1 month')->getTimestamp()]);
$this->createNode(['type' => 'article', 'created' => (new \DateTime())->modify('+3 days')->getTimestamp()]);
$this->createNode(['type' => 'article', 'created' => (new \DateTime())->modify('+1 hour')->getTimestamp()]);
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
// When I go to the blog page.
$results = views_get_view_result('blog');
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
$nids = array_map(function(ResultRow $result) {
return $result->_entity->id();
}, $results);
// The articles are ordered by post date.
2017-11-22 23:58:12 +00:00
}
2018-06-15 06:43:54 +00:00
```
---
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
```php, [.highlight: 5-9, 17-18]
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
public function testArticlesAreOrderedByDate() {
// Given that I have numerous articles with different post dates.
$this->createNode(['type' => 'article', 'created' => (new \DateTime())->modify('+1 day')->getTimestamp()]);
$this->createNode(['type' => 'article', 'created' => (new \DateTime())->modify('+1 month')->getTimestamp()]);
$this->createNode(['type' => 'article', 'created' => (new \DateTime())->modify('+3 days')->getTimestamp()]);
$this->createNode(['type' => 'article', 'created' => (new \DateTime())->modify('+1 hour')->getTimestamp()]);
// When I go to the blog page.
$results = views_get_view_result('blog');
$nids = array_map(function(ResultRow $result) {
return $result->_entity->id();
}, $results);
// The articles are ordered by post date.
$this->assertEquals([4, 1, 3, 2], $nids);
2017-11-22 23:58:12 +00:00
}
```
---
2018-06-15 06:43:54 +00:00
2017-11-22 23:58:12 +00:00
```
2018-06-15 06:43:54 +00:00
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
Testing web/modules/custom/tdd_blog/tests/src/Kernel
F 1 / 1 (100%)
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
Time: 1.42 seconds, Memory: 6.00MB
There was 1 failure:
1) Drupal\Tests\tdd_blog\Kernel\BlogPageTest::testArticlesAreOrderedByDate
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
Array (
- 0 => 4
- 1 => 1
- 2 => 3
- 3 => 2
2019-02-05 01:27:13 +00:00
+ 0 => '1'
2018-06-15 06:43:54 +00:00
+ 1 => '2'
2019-02-05 01:27:13 +00:00
+ 2 => '3'
+ 3 => '4'
2018-06-15 06:43:54 +00:00
/Users/opdavies/Code/drupal-testing-workshop/web/core/tests/Drupal/KernelTests/KernelTestBase.php:1114
/Users/opdavies/Code/drupal-testing-workshop/web/modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php:43
FAILURES!
Tests: 1, Assertions: 4, Failures: 1.
2017-11-22 23:58:12 +00:00
```
2018-06-15 06:43:54 +00:00
---
2019-02-05 01:27:13 +00:00
[.text: comic sans]
2018-06-15 06:43:54 +00:00
```[.highlight: 8-26]
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
Testing web/modules/custom/tdd_blog/tests/src/Kernel
F 1 / 1 (100%)
Time: 1.42 seconds, Memory: 6.00MB
There was 1 failure:
1) Drupal\Tests\tdd_blog\Kernel\BlogPageTest::testArticlesAreOrderedByDate
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
Array (
- 0 => 4
- 1 => 1
- 2 => 3
- 3 => 2
2019-02-05 01:27:13 +00:00
+ 0 => '1'
2018-06-15 06:43:54 +00:00
+ 1 => '2'
2019-02-05 01:27:13 +00:00
+ 2 => '3'
+ 3 => '4'
2018-06-15 06:43:54 +00:00
/Users/opdavies/Code/drupal-testing-workshop/web/core/tests/Drupal/KernelTests/KernelTestBase.php:1114
/Users/opdavies/Code/drupal-testing-workshop/web/modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php:43
FAILURES!
Tests: 1, Assertions: 4, Failures: 1.
```
---
2019-02-05 01:27:13 +00:00
![inline ](images/tdd-blog-4.png )
---
2018-06-15 06:43:54 +00:00
- _There is no sort order defined on the view_
- Add the sort order
- Re-export the view
---
2019-02-05 01:27:13 +00:00
![inline ](images/tdd-blog-5.png )
---
2018-06-15 06:43:54 +00:00
```[.highlight:3-8]
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
Testing web/modules/custom/tdd_blog/tests/src/Kernel
. 1 / 1 (100%)
Time: 1.74 seconds, Memory: 6.00MB
OK (1 test, 5 assertions)
```
2017-11-22 23:58:12 +00:00
---
2019-02-05 01:27:13 +00:00
[.build-lists: false]
2018-06-15 06:43:54 +00:00
## _Tasks_
- ~~Ensure the blog page exists~~
- ~~Ensure only published articles are shown~~
- ~~Ensure the articles are shown in the correct order~~
2017-11-22 23:58:12 +00:00
---
2019-02-05 01:27:13 +00:00
![inline fit ](images/tdd-blog-directories.png )
---
![fit ](images/tdd-blog-installed.png )
^ Using the minimal installation profile
Post 3 is unpublished
---
![inline 75% ](images/tada.png )
---
2018-06-15 06:43:54 +00:00
[.header: alignment(center)]
## Take Aways
2017-11-22 23:58:12 +00:00
---
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
- Testing has made me a _better developer_
- Testing can produce _better quality code_
- Use the _right type of test_ for the right situation
- Use the _right base class_ , use available _traits_
- Writing tests is an _investment_
- OK to _start small_ , introduce tests gradually
- Easier to _refactor_
- Tests can pass, but things can _still be broken_ . Tests only report on what they cover.
2017-10-21 12:56:01 +00:00
^ Made me think about how I'm going to do something more starting to do it
Less cruft, only write code that serves a purpose
Spending time writing tests pays dividends later on
Start by introducing tests for new features or regression tests when fixing bugs
If you know things pass, then you can refactor code knowing if something is broken
Manual testing is still important
2017-10-05 06:53:55 +00:00
---
2019-02-05 01:27:13 +00:00
[.header: alignment(center)]
2018-06-15 06:43:54 +00:00
2019-02-05 01:27:13 +00:00
## [fit] _Having tests does not mean_
## [fit] there will be no bugs
^ Only means that the tests you wrote are passing
You may not have included a certain use case
Be sure to test in the UI!
We can test what happens in a test when a user has a permission, but in our site we still need to assign the permission to a role and the role to a user.
---
### _You might be testing the wrong thing_
## Maybe it doesn't work the way you think it does
2017-11-08 06:56:37 +00:00
---
2019-02-05 01:27:13 +00:00
### _Have you written enough assertions?_
## Have you only covered the 'happy path' scenarios?
2018-06-15 06:43:54 +00:00
2019-02-05 01:27:13 +00:00
^ If your tests are passing but there is an issue, maybe you haven't written enough assertions
Be sure to check for the negative use cases too
Check that something is not included as well as what should be included
What if you pass in an incorrect value?
2018-06-15 06:43:54 +00:00
---
2019-02-05 01:27:13 +00:00
### _Other modules can affect things_
## Tests may pass, but fail when other modules are enabled
---
[.header: alignment(center)]
## [fit] _Testing may add time now_
## [fit] but save more time in the future
---
[.header: alignment(center)]
## [fit] _How do you get quicker at writing tests?_
# [fit] By writing more tests
^ Practice makes perfect
Become more familar with and knowledge of recurring errors
Find better practices and approaches. Different base classes? Less setup steps. Less time, more productive.
---
## _Start small_
## Some tests are better than no tests
---
[.background-color: #FFFFFF ]
![140% ](images/tawny-tweet-1.png )
---
[.background-color: #FFFFFF ]
![150% ](images/tawny-tweet-2.png )
---
[.text: alignment(center)]
> ![inline 150%](images/when-you-do-things-right.jpg)
2018-06-15 06:43:54 +00:00
---
[.header: alignment(center)]
2019-02-05 01:27:13 +00:00
# Questions?
2018-06-15 06:43:54 +00:00
---
[.header: alignment(center)]
# Thanks
2019-02-05 01:27:13 +00:00
### _@opdavies_
### _oliverdavies.uk_