talks/tdd-test-driven-drupal/slides.md

1846 lines
39 KiB
Markdown
Raw Normal View History

2017-10-05 06:53:55 +00:00
autoscale: true
build-lists: true
2018-06-15 06:43:54 +00:00
footer-style: alignment(left)
footer: @opdavies | oliverdavies.uk
header-emphasis: #53B0EB
header: alignment(left)
text: alignment(left)
text-emphasis: #53B0EB
theme: poster, 8
[.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
---
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)]
![right 1000%](../me-phpnw.png)
- Full stack Web Developer & System Administrator
- Senior Developer at Microserve
- Part-time freelancer
- Acquia certified Drupal 8 Grand Master
- Drupal 7 & 8 core contributor
- opdavies (Drupal.org, GitHub, Twitter)
- 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
---
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)]
## Why?
## _What?_
## How?
---
[.header: alignment(center)]
## I write _contrib modules_ for the community
---
2017-10-05 06:53:55 +00:00
2018-06-15 06:43:54 +00:00
[.header: alignment(center)]
## I write _custom modules_ for client 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
- First experience of testing with a real module
- 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)
- Crucial to preventing regressions when adding new features or fixing bugs
- Ensured consistency when porting to Drupal 8
^ Preventing regressions in my additions but also user submitted patches
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
- Piece of mind
- 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
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.
[.footer: https://www.drupal.org/core/gates#testing]
---
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
## _Testing may add time now,_ but save more <br>time in the future
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
## [fit] _How do you get quicker at writing tests?_
# [fit] By writing more tests
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
## _Testing in Drupal_
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
- _Drupal 7_ - Simpletest (testing) module provided as part of core
- _Drupal 8_ - PHPUnit added as a core dependency
- _PHPUnit Initiative_ - Simpletest to be deprecated and removed in Drupal 9
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
## _Setting up your environment_
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
- Drupal includes `core/phpunit.xml.dist`
- Copy to `core/phpunit.xml`
- Amend values as needed
+ Add base URL, database credentials
- Docksal - `fin addon install phpunit`
---
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
## _Writing Tests (Drupal 8)_
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
- PHP class with `.php` extension
- `tests/src` directory within each module
- Within the `Drupal\Tests\module_name` namespace
- Class name must match the filename
- Namespace must match the directory structure
- One test class per feature
- 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
---
2018-06-15 06:43:54 +00:00
[.hide-footer]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```php
<?php
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
// 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
---
2018-06-15 06:43:54 +00:00
## _What to test?_
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
---
2018-06-15 06:43:54 +00:00
[.background-color: #FFFFFF]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
![inline 120%](images/matt-stauffer-tweet.png)
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
## _Types of tests_
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
- Functional / FunctionalJavascript (web, browser)
- Kernel (integration)
- Unit
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
## _Functional Tests_
2017-10-21 12:56:01 +00:00
- Tests functionality
- Interacts with database
2018-06-15 06:43:54 +00:00
- Full Drupal installation
2017-10-21 12:56:01 +00:00
- Slower to run
2018-06-15 06:43:54 +00:00
- With/without JavaScript
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
^ testing profile
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
[.hide-footer]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```php
<?php
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
// modules/phpunit_example/tests/src/Functional/PHPUnitExampleMenuTest.php
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
namespace Drupal\Tests\phpunit_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 PHPUnitExampleMenuTest extends BrowserTestBase {
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
public static $modules = ['phpunit_example'];
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
public function testPhpUnitExampleMenu() {
$this->drupalGet('/examples/phpunit-example');
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
[.hide-footer]
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
```php, [.highlight: 5]
<?php
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
// modules/phpunit_example/tests/src/Functional/PHPUnitExampleMenuTest.php
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
namespace Drupal\Tests\phpunit_example\Functional;
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
use Drupal\Tests\BrowserTestBase;
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
class PHPUnitExampleMenuTest extends BrowserTestBase {
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
public static $modules = ['phpunit_example'];
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
public function testPhpUnitExampleMenu() {
$this->drupalGet('/examples/phpunit-example');
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
[.hide-footer]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```php, [.highlight: 7-9]
<?php
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
// modules/phpunit_example/tests/src/Functional/PHPUnitExampleMenuTest.php
namespace Drupal\Tests\phpunit_example\Functional;
use Drupal\Tests\BrowserTestBase;
class PHPUnitExampleMenuTest extends BrowserTestBase {
public static $modules = ['phpunit_example'];
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
public function testPhpUnitExampleMenu() {
$this->drupalGet('/examples/phpunit-example');
$this->assertSession()->statusCodeEquals(200);
}
2017-10-21 12:56:01 +00:00
}
```
---
2018-06-15 06:43:54 +00:00
[.hide-footer]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```php, [.highlight: 11]
<?php
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
// modules/phpunit_example/tests/src/Functional/PHPUnitExampleMenuTest.php
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
namespace Drupal\Tests\phpunit_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 PHPUnitExampleMenuTest extends BrowserTestBase {
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
public static $modules = ['phpunit_example'];
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
public function testPhpUnitExampleMenu() {
$this->drupalGet('/examples/phpunit-example');
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
[.hide-footer]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```php, [.highlight: 13-17]
<?php
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
// modules/phpunit_example/tests/src/Functional/PHPUnitExampleMenuTest.php
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
namespace Drupal\Tests\phpunit_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 PHPUnitExampleMenuTest extends BrowserTestBase {
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
public static $modules = ['phpunit_example'];
public function testPhpUnitExampleMenu() {
$this->drupalGet('/examples/phpunit-example');
$this->assertSession()->statusCodeEquals(200);
}
}
2017-10-21 12:56:01 +00:00
```
---
2018-06-15 06:43:54 +00:00
## _Kernel Tests_
- 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
---
2018-06-15 06:43:54 +00:00
## _Unit Tests_
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
- Tests PHP logic
- No database interaction
- Fast to run
- Tightly coupled
- Complicated mocking
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
[.hide-footer]
```php
namespace Drupal\collection_class;
2017-11-08 06:56:37 +00:00
2018-06-15 06:43:54 +00:00
class Collection implements \Countable, \IteratorAggregate {
private $items;
2017-11-08 06:56:37 +00:00
2018-06-15 06:43:54 +00:00
public function __construct($items = array()) {
$this->items = is_array($items) ? $items
: $this->getArrayableItems($items);
}
2017-11-08 06:56:37 +00:00
2018-06-15 06:43:54 +00:00
public function __toString() {
return $this->toJson();
}
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
public function all() {
return $this->items;
}
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
public function count() {
return count($this->items);
}
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
public function isEmpty() {
return empty($this->items);
}
public function first() {
return array_shift($this->items);
}
}
```
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
[.hide-footer]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```php
$collection = new Collection([1, 2, 3, 4, 5]);
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
// Returns all items.
$collection->all();
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
// Counts the number of items.
$collection->count();
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
// Returns the array keys.
$collection->keys();
```
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
[.hide-footer]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```php
public function testAll() {
$items = ['foo', 'bar', 'baz'];
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
$collection = new Collection($items);
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
$this->assertEqual($items, $collection->all());
}
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
2018-06-15 06:43:54 +00:00
## _Setup (functional)_
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
[.hide-footer]
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
---
2018-06-15 06:43:54 +00:00
## _Assertions_
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
[.hide-footer]
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()
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
```
---
2018-06-15 06:43:54 +00:00
## _Assertions (functional)_
2017-11-22 23:58:12 +00:00
2018-06-15 06:43:54 +00:00
[.hide-footer]
2017-10-21 12:56:01 +00:00
```php
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
2018-06-15 06:43:54 +00:00
## _Specification_
- Job adverts created on third-party system, needs to create nodes in Drupal, links users to separate application system
- Adverts need to be linked to offices
- Advert length specified in number of days
- 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
---
2018-06-15 06:43:54 +00:00
[.hide-footer]
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
---
2018-06-15 06:43:54 +00:00
## _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
- Added 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
---
2018-06-15 06:43:54 +00:00
## _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
---
2018-06-15 06:43:54 +00:00
## _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
---
2018-06-15 06:43:54 +00:00
## _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
---
2018-06-15 06:43:54 +00:00
![fit](images/simpletest-1.png)
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
![fit](images/simpletest-2.png)
2017-10-05 06:53:55 +00:00
---
2018-06-15 06:43:54 +00:00
![fit](images/simpletest-3.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
2018-06-15 06:43:54 +00:00
![fit](images/simpletest-4.png)
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
2018-06-15 06:43:54 +00:00
```
vendor/bin/phpunit -c core path/to/module
vendor/bin/phpunit -c core path/to/module --filter testSomething
vendor/bin/phpunit -c core path/to/module --verbose
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
## _Test Driven_<br> Development
2017-10-05 06:53:55 +00:00
---
2018-06-15 06:43:54 +00:00
## _Test Driven Development_
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
- Write a test
- See it fail
- Write code until test passes
- Refactor when tests are green
- 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
2018-06-15 06:43:54 +00:00
## _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
---
2018-06-15 06:43:54 +00:00
## _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
- Write assertions first, sometimes
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
2018-06-15 06:43:54 +00:00
## Building a new _Drupal 8 Module_ with _TDD_
2017-10-21 12:56:01 +00:00
---
2018-06-15 06:43:54 +00:00
## _Acceptance criteria_
- 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
---
2018-06-15 06:43:54 +00:00
## _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
2018-06-15 06:43:54 +00:00
## _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
---
2018-06-15 06:43:54 +00:00
[.hide-footer]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```yml
# tdd_blog.info.yml
name: 'TDD Example'
core: '8.x'
type: 'module'
2017-10-21 12:56:01 +00:00
```
---
2018-06-15 06:43:54 +00:00
### _Task 1:_
## Ensure the blog page exists
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
---
[.hide-footer]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```php
<?php
2017-10-21 12:56:01 +00:00
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'];
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
[.hide-footer]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```php, [.highlight: 5]
<?php
2017-10-21 12:56:01 +00:00
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
---
2018-06-15 06:43:54 +00:00
[.hide-footer]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```php, [.highlight: 7-9]
<?php
2017-10-21 12:56:01 +00:00
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
}
```
---
2018-06-15 06:43:54 +00:00
[.hide-footer]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```php, [.highlight: 11]
<?php
2017-10-21 12:56:01 +00:00
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);
}
}
```
---
[.hide-footer]
```php, [.highlight: 13-17]
<?php
// 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);
}
}
```
---
[.hide-footer]
```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.
```
---
[.hide-footer]
```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
[.hide-footer]
```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
[.hide-footer]
```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
---
[.hide-footer]
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_
- Create a new view
- Set the path
- Export the config
- Copy it into the module's `config/install` directory
---
[.hide-footer]
```[.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.
```
---
[.hide-footer]
```yml,[.highlight: 1, 7-10]
# tdd_blog.info.yml
name: 'TDD Dublin'
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
[.hide-footer]
```[.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
---
[.hide-footer]
```[.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
```
---
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
---
### _Task 2:_
## Ensure only published articles are shown
---
[.hide-footer]
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
}
```
---
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
### _Option 1:_ Functional tests
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
---
[.hide-footer]
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
[.hide-footer]
```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
2018-06-15 06:43:54 +00:00
[.hide-footer]
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
}
```
---
2018-06-15 06:43:54 +00:00
[.header: alignment(center)]
### _Option 2:_ Kernel tests
---
[.hide-footer]
2017-10-21 12:56:01 +00:00
```php
2018-06-15 06:43:54 +00:00
<?php
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
---
2018-06-15 06:43:54 +00:00
[.hide-footer]
```php, [.highlight: 3-8]
<?php
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
}
```
---
2018-06-15 06:43:54 +00:00
[.hide-footer]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```php, [.highlight: 10]
<?php
2017-10-21 12:56:01 +00:00
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
```
---
2018-06-15 06:43:54 +00:00
[.hide-footer]
2017-10-21 12:56:01 +00:00
2018-06-15 06:43:54 +00:00
```php, [.highlight: 14-18]
<?php
2017-10-21 12:56:01 +00:00
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
[.hide-footer]
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
[.hide-footer]
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
[.hide-footer]
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
---
2018-06-15 06:43:54 +00:00
[.hide-footer]
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
[.hide-footer]
```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
[.hide-footer]
```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
[.hide-footer]
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
Failed asserting that actual size 3 matches expected size 1.
/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
[.hide-footer]
```[.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
Failed asserting that actual size 3 matches expected size 1.
/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
2018-06-15 06:43:54 +00:00
>- _There are no filters on the view_
- Add the filters
- Export and save the view
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
```
---
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
---
### _Task 3:_
## Ensure the articles are shown in the correct order
2017-11-22 23:58:12 +00:00
---
2018-06-15 06:43:54 +00:00
[.hide-footer]
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
[.hide-footer]
```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.
$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.
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
[.hide-footer]
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
[.hide-footer]
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
```
---
[.hide-footer]
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
[.hide-footer]
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
+ 0 => '3'
+ 1 => '2'
+ 2 => '4'
+ 3 => '1'
/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
---
[.hide-footer]
```[.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
+ 0 => '3'
+ 1 => '2'
+ 2 => '4'
+ 3 => '1'
/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.
```
---
- _There is no sort order defined on the view_
- Add the sort order
- Re-export the view
---
```[.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
---
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
---
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
---
2018-06-15 06:43:54 +00:00
[.hide-footer]
[.text: alignment(center)]
> ![inline 150%](images/when-you-do-things-right.jpg)
2017-11-08 06:56:37 +00:00
---
2018-06-15 06:43:54 +00:00
## _Resources_
- github.com/opdavies/drupal-module-tdd-dublin
- drupalize.me/series/testing-drupal-7-simpletest
- lullabot.com/articles/an-overview-of-testing-in-drupal-8
- mediacurrent.com/blog/writing-simple-simpletest-tests-your-d7-module
- mediacurrent.com/blog/writing-simple-phpunit-tests-your-d8-module
- knpuniversity.com/screencast/phpunit
- adamwathan.me/test-driven-laravel
- laracasts.com
---
- oliverdavies.uk/_talks_
- oliverdavies.uk/_twitter_
- oliverdavies.uk/_drupal_
- oliverdavies.uk/_github_
- oliverdavies.uk/_youtube_
---
[.header: alignment(center)]
## Questions?
---
[.header: alignment(center)]
# Thanks