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

1257 lines
22 KiB
Markdown
Raw Normal View History

2017-10-05 06:53:55 +00:00
autoscale: true
build-lists: true
2017-11-22 23:58:12 +00:00
theme: simple, 1
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
2017-11-22 23:58:12 +00:00
# __TDD - Test Driven Drupal__
2017-10-05 06:53:55 +00:00
---
2017-11-08 06:56:37 +00:00
[.build-lists: false]
2017-10-21 12:56:01 +00:00
- PHP code
- Mixture of D7 and D8
- SimpleTest (D7)
- PHPUnit (D8)
2017-10-05 06:53:55 +00:00
---
[.build-lists: false]
- Senior Developer at Microserve
2017-10-21 12:56:01 +00:00
- Contrib module maintainer
- Occasional core contributor
- Sticker collector and elePHPant herder
2017-10-05 06:53:55 +00:00
- @opdavies
- oliverdavies.uk
2017-11-08 06:56:37 +00:00
![right](../me-phpnw.png)
---
## I write and release contrib modules for the community.<br><br>
## I write custom modules for client projects.
2017-10-21 12:56:01 +00:00
---
![inline fit](images/timmillwood-ono.png)
^ First experience of testing with a real module.
Used on 11,046 sites (84 D5, 7,094 D6, 3,868 D7).
Currently used on 28,398 (10 D5, 2,207 D6, 23,206 D7, 2,975 D8).
Tests crucial to preventing regressions when adding new features or fixing bugs.
---
2017-11-22 23:58:12 +00:00
## __Why Test?__
2017-10-21 12:56:01 +00:00
- Catch bugs earlier
- Piece of mind
- Prevent regressions
- Write less code
- Documentation
- Drupal core requirement - <https://www.drupal.org/core/gates#testing>
- 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
---
2017-11-22 23:58:12 +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]
---
2017-11-22 23:58:12 +00:00
## __Testing in Drupal - SimpleTest__
2017-10-21 12:56:01 +00:00
- Based on <http://www.SimpleTest.org>
- In D7 core
- `*.test` files
- All test classes in one file
---
2017-11-22 23:58:12 +00:00
## __Testing in Drupal - PHPUnit__
2017-10-21 12:56:01 +00:00
- Used in other PHP projects (e.g. Symfony, Laravel)
- In D8 core, but not default
- `*.php` files
- One test class per file
---
2017-11-22 23:58:12 +00:00
## __The PHPUnit Initiative__
2017-10-21 12:56:01 +00:00
- <https://www.drupal.org/node/2807237>
- D8 core tests to change to PHPUnit
- Deprecate SimpleTest, remove in D9
- "A big chunk of old tests" converted on Feb 21st
---
2017-11-22 23:58:12 +00:00
## __The PHPUnit Initiative__
2017-10-21 12:56:01 +00:00
As part of the PHPUnit initiative __a considerable part of Simpletests will be converted to PHPUnit based browser tests on February 21st 2017__. A backwards compatibility layer has been implemented so that many Simpletests can be converted by just using the new BrowserTestBase base class and moving the test file. There is also a script to automatically convert test files in the conversion issue.
__Developers are encouraged to use BrowserTestBase instead of Simpletest as of Drupal 8.3.0__, but both test systems are fully supported during the Drupal 8 release cycle.
The timeline for the deprecation of Simpletest's WebTestBase is under discussion.
[.footer: https://groups.drupal.org/node/516229]
---
2017-11-22 23:58:12 +00:00
## __Types of Tests__
---
## __Unit Tests__
2017-10-21 12:56:01 +00:00
- `UnitTestCase`
- Tests PHP logic
- No database interaction
- Fast to run
---
2017-11-22 23:58:12 +00:00
## __Unit Tests__
2017-10-21 12:56:01 +00:00
2017-11-22 23:58:12 +00:00
__Pros:__
2017-10-21 12:56:01 +00:00
- Verify individual parts
- Quickly find problems in code
- Fast execution
- No system setup for the test run
---
2017-11-22 23:58:12 +00:00
## __Unit Tests__
2017-10-21 12:56:01 +00:00
2017-11-22 23:58:12 +00:00
__Cons:__
2017-10-21 12:56:01 +00:00
- Rewrite on every refactoring
- Complicated mocking
- No guarantee that the whole system actually works
---
2017-11-22 23:58:12 +00:00
## __Kernel Tests__
2017-10-21 12:56:01 +00:00
- Kernel tests are integration tests that test on components. You can install modules.
- `KernelTestBase`
[.footer: https://www.drupal.org/docs/8/testing/types-of-tests-in-drupal-8]
---
2017-11-22 23:58:12 +00:00
## __Kernel Tests__
2017-10-21 12:56:01 +00:00
2017-11-22 23:58:12 +00:00
__Pros:__
2017-10-21 12:56:01 +00:00
- Verify that components actually work together
- Somewhat easy to locate bugs
---
2017-11-22 23:58:12 +00:00
## __Kernel Tests__
2017-10-21 12:56:01 +00:00
2017-11-22 23:58:12 +00:00
__Cons:__
2017-10-21 12:56:01 +00:00
- Slower execution
- System setup required
- No guarantee that end user features actually work
---
2017-11-22 23:58:12 +00:00
## __UI Tests__
2017-10-21 12:56:01 +00:00
2017-11-22 23:58:12 +00:00
- Web/Functional/FunctionalJavascript
2017-10-21 12:56:01 +00:00
- `DrupalWebTestCase` (D7)
- `WebTestBase`, `BrowserTestBase`, `JavascriptTestBase` (D8)
- Tests functionality
- Interacts with database
- Slower to run
- With/without JavaScript (D8)
^ - Use JavascriptTestBase when you need to test how the system works for a user with Javascript enabled.
---
2017-11-22 23:58:12 +00:00
## __Test Driven Development (TDD)__
2017-10-21 12:56:01 +00:00
- Write a test, see it fail
- Write code until test passes
- Repeat
- Refactor when tests are green
![right 100%](images/tdd-circle-of-life.png)
[.footer: http://www.agilenutshell.com/assets/test-driven-development/tdd-circle-of-life.png]
^ "Grab for green."
Not the only way
Write code beforehand and test afterwards
Write code first, comment out/reset branch, then TDD
---
2017-11-22 23:58:12 +00:00
## __Porting Modules to Drupal 8__
2017-10-21 12:56:01 +00:00
- Make a new branch
`git checkout --orphan 8.x-1.x`
- Add/update the tests
- Write code to make the tests pass
- Refactor
- Repeat
---
2017-11-22 23:58:12 +00:00
## __Writing Tests (SimpleTest)__
2017-10-21 12:56:01 +00:00
---
2017-11-22 23:58:12 +00:00
2017-10-21 12:56:01 +00:00
```ini
# example.info
name = Example
core = 7.x
files[] = example.test
```
---
2017-11-22 23:58:12 +00:00
2017-10-21 12:56:01 +00:00
```php
// example.test
class ExampleTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Example tests',
'description' => 'Web tests for the example module.',
'group' => 'Example',
);
}
}
```
---
2017-11-22 23:58:12 +00:00
```php, [.highlight: 5-7]
2017-10-21 12:56:01 +00:00
class ExampleTestCase extends DrupalWebTestCase {
...
public function testSomething {
$this->assertTrue(TRUE);
}
}
```
---
2017-11-22 23:58:12 +00:00
## __Writing Tests (PHPUnit)__
2017-10-21 12:56:01 +00:00
- No need to load test classes expicitly.
- Add classes into `tests/src` directory.
- Extend `BrowserTestBase`.
- No `getInfo` method.
^ Classes get autoloaded PSR-4
---
2017-11-22 23:58:12 +00:00
## __Creating the World__
2017-10-21 12:56:01 +00:00
```php
public function setUp() {
// Enable any other required modules.
parent::setUp(['foo', 'bar']);
// Anything else we need to do.
}
```
---
2017-11-22 23:58:12 +00:00
## __Creating the World__
2017-10-21 12:56:01 +00:00
```php
$this->drupalCreateUser();
$this->drupalLogin();
$this->drupalCreateNode();
$this->drupalLogout();
```
---
2017-11-22 23:58:12 +00:00
## __Assertions__
2017-10-21 12:56:01 +00:00
- `assertTrue`
- `assertFalse`
- `assertNull`
- `assertNotNull`
- `assertEqual`
`assertEquals`
---
2017-11-22 23:58:12 +00:00
## __Assertions__
2017-10-21 12:56:01 +00:00
- `assertRaw`
- `assertResponse`
`assertSession()->statusCodeEquals()`
- `assertField`
- `assertFieldById`
- `assertTitle`
---
2017-11-22 23:58:12 +00:00
## __Assertions__
2017-11-08 06:56:37 +00:00
- `assertText`
`assertSession()->pageTextContains()`
- `assertNoText`
`assertSession()->pageTextNotContains()`
---
2017-11-22 23:58:12 +00:00
# __Running Tests__
2017-10-21 12:56:01 +00:00
---
2017-11-22 23:58:12 +00:00
## __SimpleTest UI__
2017-10-21 12:56:01 +00:00
---
![fit](images/simpletest-1.png)
---
![fit](images/simpletest-2.png)
---
![fit](images/simpletest-3.png)
---
![fit](images/simpletest-4.png)
---
2017-11-22 23:58:12 +00:00
## __Running SimpleTest (CLI)__
2017-10-21 12:56:01 +00:00
```bash
# Drupal 7
$ php scripts/run-tests.sh
# Drupal 8
$ php core/scripts/run-tests.sh
```
---
2017-11-22 23:58:12 +00:00
## __Running SimpleTest (CLI)__
2017-10-21 12:56:01 +00:00
```bash
--color
--verbose
--all
--module
--class
--file
```
---
2017-11-22 23:58:12 +00:00
## __Running PHPUnit__
2017-10-21 12:56:01 +00:00
```bash
2017-11-22 23:58:12 +00:00
# Assumes you have a configured phpunit.xml file.
2017-10-21 12:56:01 +00:00
$ vendor/bin/phpunit
$ vendor/bin/phpunit [directory]
$ vendor/bin/phpunit --filter [method]
2017-11-22 23:58:12 +00:00
$ vendor/bin/phpunit --verbose --debug
2017-10-21 12:56:01 +00:00
```
2017-11-22 23:58:12 +00:00
^ Either need to be inside "core" directory or use "-c core"
2017-10-21 12:56:01 +00:00
---
2017-11-22 23:58:12 +00:00
## __Example: Collection Class__
2017-10-21 12:56:01 +00:00
---
2017-11-22 23:58:12 +00:00
## __Collection Class__
2017-10-21 12:56:01 +00:00
- <http://dgo.to/collection_class>
- Adds a `Collection` class, based on Laravels
- Provides helper methods for array methods
- Drupal 7, uses xautoload
2017-11-22 23:58:12 +00:00
- All unit tests
2017-10-21 12:56:01 +00:00
^ xautoload gives PSR-4 namespaces and autoloading similar to Drupal 8.
---
2017-11-22 23:58:12 +00:00
2017-10-21 12:56:01 +00:00
```php
$collection = collect([1, 2, 3, 4, 5]);
// Returns all items.
$collection->all();
// Counts the number of items.
$collection->count();
// Returns the array keys.
$collection->keys();
```
---
2017-11-22 23:58:12 +00:00
2017-10-21 12:56:01 +00:00
```php
namespace Drupal\collection_class;
class Collection implements \Countable, \IteratorAggregate {
private $items;
public function __construct($items = array()) {
$this->items = is_array($items) ? $items
: $this->getArrayableItems($items);
}
public function __toString() {
return $this->toJson();
}
...
```
---
2017-11-22 23:58:12 +00:00
2017-10-21 12:56:01 +00:00
```php
public function all() {
return $this->items;
}
public function count() {
return count($this->items);
}
public function isEmpty() {
return empty($this->items);
}
public function first() {
return array_shift($this->items);
}
```
---
2017-11-22 23:58:12 +00:00
## __Testing__
2017-10-21 12:56:01 +00:00
```php
public function setUp() {
$this->firstCollection = collect(['foo', 'bar', 'baz']);
$this->secondCollection = collect([
array('title' => 'Foo', 'status' => 1),
array('title' => 'Bar', 'status' => 0),
array('title' => 'Baz', 'status' => 1)
]);
parent::setUp();
}
```
2017-10-05 06:53:55 +00:00
---
2017-11-22 23:58:12 +00:00
## __Testing__
2017-10-21 12:56:01 +00:00
```php
public function testCollectFunction() {
$this->assertEqual(
get_class($this->firstCollection),
'Drupal\collection_class\Collection'
);
}
```
---
2017-11-22 23:58:12 +00:00
## __Testing__
2017-10-21 12:56:01 +00:00
```php
public function testAll() {
$this->assertEqual(
array('foo', 'bar', 'baz'),
$this->firstCollection->all()
);
}
```
---
2017-11-22 23:58:12 +00:00
## __Testing__
2017-10-21 12:56:01 +00:00
```php
public function testCount() {
$this->assertEqual(
3,
$this->firstCollection->count()
);
}
```
---
2017-11-22 23:58:12 +00:00
## __Testing__
2017-10-21 12:56:01 +00:00
```php
public function testMerge() {
$first = collect(array('a', 'b', 'c'));
$second = collect(array('d', 'e', 'f'));
$this->assertEqual(
array('a', 'b', 'c', 'd', 'e', 'f'),
$first->merge($second)->all()
);
}
```
---
![fit](images/collection-class-1.png)
---
![fit](images/collection-class-2.png)
---
2017-11-22 23:58:12 +00:00
## __Example: Toggle Optional Fields__
2017-10-05 06:53:55 +00:00
---
2017-11-22 23:58:12 +00:00
## __Toggle Optional Fields__
2017-10-21 12:56:01 +00:00
- <http://dgo.to/toggle_optional_fields>
- Adds a button to toggle optional fields on node forms using form alters
- Possible to override using an custom alter hook
- Uses unit and web tests
![right 85%](images/toggle-optional-fields-button.png)
---
```php
// Looping through available form elements...
// Only affect fields.
if (!toggle_optional_fields_element_is_field($element_name)) {
return;
}
$element = &$form[$element_name];
if (isset($overridden_fields[$element_name])) {
return $element['#access'] = $overridden_fields[$element_name];
}
// If the field is not required, disallow access to hide it.
if (isset($element[LANGUAGE_NONE][0]['#required'])) {
return $element['#access'] = !empty($element[LANGUAGE_NONE][0]['#required']);
}
```
---
2017-11-22 23:58:12 +00:00
## __What to Test?__
2017-10-21 12:56:01 +00:00
- **Functional:** Are the correct fields shown and hidden?
- **Unit:** Is the field name check returning correct results?
2017-10-05 06:53:55 +00:00
---
2017-11-22 23:58:12 +00:00
## __Unit Tests__
2017-10-21 12:56:01 +00:00
```php
// Returns TRUE or FALSE to indicate if this is a field.
function toggle_optional_fields_element_is_field($name) {
if (in_array($name, array('body', 'language'))) {
return TRUE;
}
return substr($name, 0, 6) == 'field_';
}
```
---
2017-11-22 23:58:12 +00:00
## __Unit Tests__
```php
public function testElementNameIsField() {
...
$this->assertTrue(
toggle_optional_fields_element_is_field('field_tags')
);
$this->assertTrue(
toggle_optional_fields_element_is_field('body')
);
2017-10-21 12:56:01 +00:00
2017-11-22 23:58:12 +00:00
$this->assertFalse(
toggle_optional_fields_element_is_field('title')
);
}
```
---
## __Unit Tests__
2017-10-21 12:56:01 +00:00
```php
2017-11-22 23:58:12 +00:00
public function testElementNameIsField() {
...
2017-10-21 12:56:01 +00:00
2017-11-22 23:58:12 +00:00
foreach ($this->elementNameDataProvider() as $data) {
list($element_name, $expected_result) = $data;
2017-10-21 12:56:01 +00:00
2017-11-22 23:58:12 +00:00
$this->assertEquals(
$expected_result,
toggle_optional_fields_element_is_field($element_name)
);
}
}
private function elementNameDataProvider() {
return array(
array('body', TRUE),
array('field_tags', TRUE),
array('title', FALSE),
);
}
2017-10-21 12:56:01 +00:00
```
---
![fit](images/toggle-optional-fields-1.png)
---
2017-11-22 23:58:12 +00:00
## __Web Tests__
2017-10-21 12:56:01 +00:00
```php
public function setUp() {
parent::setUp();
$this->drupalLogin(
$this->drupalCreateUser(array(
'create article content',
'create page content'
));
);
// Enable toggling on article node forms.
variable_set('toggle_optional_fields_node_types', array('article'));
$this->refreshVariables();
}
```
---
2017-11-22 23:58:12 +00:00
## __Custom Assertions__
2017-10-21 12:56:01 +00:00
```php
private function assertTagsFieldNotHidden() {
$this->assertFieldByName(
'field_tags[und]',
NULL,
t('Tags field visible.')
);
}
```
---
2017-11-22 23:58:12 +00:00
## __Testing Hidden Fields__
2017-10-21 12:56:01 +00:00
```php
public function testFieldsHiddenByDefault() {
variable_set('toggle_optional_fields_hide_by_default', TRUE);
$this->refreshVariables();
$this->drupalGet('node/add/article');
$this->assertShowOptionalFieldsButtonFound();
$this->assertHideOptionalFieldsButtonNotFound();
$this->assertTagsFieldHidden();
...
```
---
2017-11-22 23:58:12 +00:00
## __Testing Hidden Fields__
2017-10-21 12:56:01 +00:00
```php
...
$this->drupalPost(
'node/add/article',
array(),
t('Show optional fields')
);
$this->assertHideOptionalFieldsButtonFound();
$this->assertShowOptionalFieldsButtonNotFound();
$this->assertTagsFieldNotHidden();
}
```
---
![fit](images/toggle-optional-fields-2.png)
---
![fit](images/toggle-optional-fields-3.png)
---
2017-11-22 23:58:12 +00:00
# __Building a new Drupal <br>8 Module with TDD__
2017-10-21 12:56:01 +00:00
---
As a site visitor
I want to see a list of all published pages at `/pages`
Ordered alphabetically by title.
---
```yml
2017-10-21 22:15:22 +00:00
# tdd_dublin.info.yml
2017-10-21 12:56:01 +00:00
name: DrupalCamp Dublin test
core: 8.x
type: module
```
---
```php
// tests/src/Functional/ListingPageTest.php
class ListingPageTest extends BrowserTestBase {
2017-10-21 22:15:22 +00:00
protected static $modules = ['tdd_dublin'];
2017-10-21 12:56:01 +00:00
public function testListingPageExists() {
$this->drupalGet('pages');
$this->assertSession()->statusCodeEquals(200);
}
}
```
---
```
2017-11-22 23:58:12 +00:00
docker@cli:/var/www$ vendor/bin/phpunit -c core modules/tdd_dublin/tests
2017-10-21 12:56:01 +00:00
PHPUnit 4.8.36 by Sebastian Bergmann and contributors.
2017-11-22 23:58:12 +00:00
Testing modules/tdd_dublin/tests/
2017-10-21 12:56:01 +00:00
E
Time: 25.94 seconds, Memory: 6.00MB
There was 1 error:
1) PageListTest::testListingPage
Behat\Mink\Exception\ExpectationException: Current response status code is 404,
but 200 expected.
/var/www/vendor/behat/mink/src/WebAssert.php:770
/var/www/vendor/behat/mink/src/WebAssert.php:130
2017-10-21 22:15:22 +00:00
/var/www/modules/tdd_dublin/tests/src/PageListTest.php:11
2017-10-21 12:56:01 +00:00
```
---
- Add the view.
2017-11-22 23:58:12 +00:00
- Copy the config into the modules `config/install`.
2017-10-21 12:56:01 +00:00
---
```
2017-11-22 23:58:12 +00:00
docker@cli:/var/www$ vendor/bin/phpunit -c core modules/tdd_dublin/tests
2017-10-21 12:56:01 +00:00
PHPUnit 4.8.36 by Sebastian Bergmann and contributors.
2017-11-22 23:58:12 +00:00
Testing modules/tdd_dublin/tests/
2017-10-21 12:56:01 +00:00
E
Time: 19.07 seconds, Memory: 6.00MB
There was 1 error:
1) PageListTest::testListingPage
Drupal\Core\Config\UnmetDependenciesException:
2017-10-21 22:15:22 +00:00
Configuration objects provided by <em class="placeholder">tdd_dublin</em>
2017-10-21 12:56:01 +00:00
have unmet dependencies:
<em class="placeholder">node.type.page (node),
views.view.pages (node, views)</em>
```
---
```yml
name: DrupalCamp Dublin tests
core: 8.x
type: module
dependencies:
- drupal:node
- drupal:views
```
---
```
2017-11-22 23:58:12 +00:00
docker@cli:/var/www$ vendor/bin/phpunit -c core modules/tdd_dublin/tests
2017-10-21 12:56:01 +00:00
PHPUnit 4.8.36 by Sebastian Bergmann and contributors.
2017-11-22 23:58:12 +00:00
Testing modules/tdd_dublin/tests/
2017-10-21 12:56:01 +00:00
.
Time: 29.58 seconds, Memory: 6.00MB
OK (1 test, 1 assertion)
```
---
```php
public function testOnlyPublishedPagesAreShown() {
// Given I have a mixture of published and unpublished pages,
// as well as other types of content.
// When I view the pages list.
// I should only see the published pages.
}
```
---
```php
public function testOnlyPublishedPagesAreShown() {
$this->drupalCreateContentType(['type' => 'article']);
2017-11-22 23:58:12 +00:00
$nodeA = $this->drupalCreateNode(['type' => 'page', 'status' => TRUE]);
$nodeB = $this->drupalCreateNode(['type' => 'article']);
$nodeC = $this->drupalCreateNode(['type' => 'page', 'status' => FALSE]);
2017-10-21 12:56:01 +00:00
// When I view the pages list.
// I should only see the published pages.
}
```
---
2017-11-08 06:56:37 +00:00
```php
public function testOnlyPublishedPagesAreShown() {
...
2017-11-22 23:58:12 +00:00
$this->drupalGet('/pages');
$this->assertSession()->statusCodeEquals(200);
2017-11-08 06:56:37 +00:00
2017-11-22 23:58:12 +00:00
$this->assertSession()->pageTextContains($nodeA->label());
2017-11-08 06:56:37 +00:00
2017-11-22 23:58:12 +00:00
$this->assertSession()->pageTextNotContains($nodeB->label());
$this->assertSession()->pageTextNotContains($nodeC->label());
2017-11-08 06:56:37 +00:00
}
```
---
2017-10-21 12:56:01 +00:00
```php
public function testOnlyPublishedPagesAreShown() {
2017-11-22 23:58:12 +00:00
$this->drupalCreateContentType(['type' => 'article']);
$this->drupalCreateNode(['type' => 'page', 'status' => TRUE]);
$this->drupalCreateNode(['type' => 'article']);
$this->drupalCreateNode(['type' => 'page', 'status' => FALSE]);
2017-10-21 12:56:01 +00:00
$results = views_get_view_result('pages');
2017-11-22 23:58:12 +00:00
$nids = array_column($results, 'nid'); // [1, 3]
2017-10-21 12:56:01 +00:00
// I should only see the published pages.
}
```
---
```php
public function testOnlyPublishedPagesAreShown() {
2017-11-22 23:58:12 +00:00
$this->drupalCreateContentType(['type' => 'article']);
$this->drupalCreateNode(['type' => 'page', 'status' => TRUE]);
$this->drupalCreateNode(['type' => 'article']);
$this->drupalCreateNode(['type' => 'page', 'status' => FALSE]);
2017-10-21 12:56:01 +00:00
$results = views_get_view_result('pages');
2017-11-22 23:58:12 +00:00
$nids = array_column($results, 'nid'); // [1, 3]
2017-10-21 12:56:01 +00:00
$this->assertEquals([1], $nids);
}
```
---
```
2017-11-22 23:58:12 +00:00
docker@cli:/var/www$ vendor/bin/phpunit -c core modules/tdd_dublin/tests
2017-10-21 12:56:01 +00:00
--filter=testOnlyPublishedPagesAreShown
PHPUnit 4.8.36 by Sebastian Bergmann and contributors.
2017-11-22 23:58:12 +00:00
Testing modules/tdd_dublin/tests
2017-10-21 12:56:01 +00:00
F
Time: 26.4 seconds, Memory: 6.00MB
There was 1 failure:
```
---
```
1) PageListTest::testOnlyPublishedPagesAreShown
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
Array (
- 0 => 1
+ 0 => '1'
+ 1 => '3'
)
2017-11-22 23:58:12 +00:00
/var/www/tests/Drupal/Tests/BrowserTestBase.php:1240
2017-10-21 22:15:22 +00:00
/var/www/modules/tdd_dublin/tests/src/PageListTest.php:25
2017-10-21 12:56:01 +00:00
FAILURES!
Tests: 1, Assertions: 3, Failures: 1.
```
---
[.build-lists: false]
- Edit the view
- Add the status filter
- Update the module config
---
```
2017-11-22 23:58:12 +00:00
docker@cli:/var/www$ vendor/bin/phpunit -c core modules/tdd_dublin/tests
2017-10-21 12:56:01 +00:00
--filter=testOnlyPublishedPagesAreShown
PHPUnit 4.8.36 by Sebastian Bergmann and contributors.
2017-11-22 23:58:12 +00:00
Testing modules/tdd_dublin/tests
2017-10-21 12:56:01 +00:00
.
Time: 26.53 seconds, Memory: 6.00MB
OK (1 test, 3 assertions)
```
---
```php
public function testPagesAreOrderedAlphabetically() {
// Given I have multiple pages with different titles.
// When I view the pages list.
// I see the pages in the correct order.
}
```
---
```php
public function testPagesAreOrderedAlphabetically() {
$this->drupalCreateNode(['title' => 'Page A']);
$this->drupalCreateNode(['title' => 'Page D']);
$this->drupalCreateNode(['title' => 'Page B']);
$this->drupalCreateNode(['title' => 'Page C']);
$results = views_get_view_result('pages');
2017-11-08 06:56:37 +00:00
$nids = array_column($results, 'nid');
2017-10-21 12:56:01 +00:00
$this->assertEquals([1, 3, 4, 2], $nids);
}
```
2017-10-05 06:53:55 +00:00
---
2017-10-21 12:56:01 +00:00
```
2017-11-22 23:58:12 +00:00
docker@cli:/var/www$ vendor/bin/phpunit -c core modules/tdd_dublin/tests
2017-10-21 12:56:01 +00:00
-filter=testPagesAreOrderedAlphabetically
PHPUnit 4.8.36 by Sebastian Bergmann and contributors.
2017-11-22 23:58:12 +00:00
Testing modules/tdd_dublin/tests
2017-10-21 12:56:01 +00:00
F
2017-10-05 06:53:55 +00:00
2017-10-21 12:56:01 +00:00
Time: 28.03 seconds, Memory: 6.00MB
There was 1 failure:
```
2017-10-05 06:53:55 +00:00
---
2017-10-21 12:56:01 +00:00
```
1) PageListTest::testPagesAreOrderedAlphabetically
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
Array (
- 0 => 1
- 1 => 3
- 2 => 4
- 3 => 2
+ 0 => '1'
+ 1 => '2'
+ 2 => '3'
+ 3 => '4'
)
2017-10-05 06:53:55 +00:00
2017-11-22 23:58:12 +00:00
/var/www/tests/Drupal/Tests/BrowserTestBase.php:1240
2017-10-21 22:15:22 +00:00
/var/www/modules/tdd_dublin/tests/src/PageListTest.php:36
2017-10-21 12:56:01 +00:00
```
2017-10-05 06:53:55 +00:00
---
2017-10-21 12:56:01 +00:00
- Edit the view
- Remove the default sort criteria (created on)
- Add new sort criteria
- Update the module config
---
```
2017-11-22 23:58:12 +00:00
docker@cli:/var/www$ vendor/bin/phpunit -c core modules/tdd_dublin/tests
2017-10-21 12:56:01 +00:00
--filter=testPagesAreOrderedAlphabetically
PHPUnit 4.8.36 by Sebastian Bergmann and contributors.
2017-11-22 23:58:12 +00:00
Testing modules/tdd_dublin/tests
2017-10-21 12:56:01 +00:00
.
Time: 27.67 seconds, Memory: 6.00MB
OK (1 test, 2 assertions)
```
---
```
2017-11-22 23:58:12 +00:00
docker@cli:/var/www$ vendor/bin/phpunit -c core modules/tdd_dublin/tests
2017-10-21 12:56:01 +00:00
PHPUnit 4.8.36 by Sebastian Bergmann and contributors.
2017-11-22 23:58:12 +00:00
Testing modules/tdd_dublin/tests
2017-10-21 12:56:01 +00:00
...
Time: 1.17 minutes, Memory: 6.00MB
OK (3 tests, 6 assertions)
```
---
2017-11-22 23:58:12 +00:00
## __Downgrading to Kernel Tests__
---
```php
// tests/src/Kernel/PageListTest.php
namespace Drupal\Tests\tdd_dublin\Kernel;
use Drupal\KernelTests\KernelTestBase;
class PageListTest extends KernelTestBase {
}
```
---
```php
public function testOnlyPublishedPagesAreShown() {
$nids = array_column(views_get_view_result('pages'), 'nid');
$this->assertEquals([1], $nids);
}
```
^ Started with assertions and worked backwards
"Outside in"
---
```php
protected static $modules = [
'node',
'system',
'tdd_dublin',
'user',
'views'
];
protected function setUp() {
parent::setUp();
$this->installConfig(['tdd_dublin']);
$this->installEntitySchema('node');
$this->installEntitySchema('user');
}
```
---
```php
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
public function testOnlyPublishedPagesAreShown() {
NodeType::create(['type' => 'article', 'name' => t('Article')]);
Node::create($this->getValidParams(['status' => TRUE]))->save();
Node::create($this->getValidParams(['type' => 'article']))->save();
Node::create($this->getValidParams(['status' => FALSE]))->save();
$nids = array_column(views_get_view_result('pages'), 'nid');
$this->assertEquals([1], $nids);
}
private function getValidParams(array $overrides = []) {
return array_merge([
'status' => TRUE,
'title' => $this->randomString(),
'type' => 'page',
], $overrides);
}
```
---
```
Testing modules/custom/tdd_dublin/tests/src/Kernel
.
Time: 8.9 seconds, Memory: 6.00MB
OK (1 test, 4 assertions)
```
^ Previously 26 seconds
---
![inline fit](images/kernel-tests.png)
---
## __Demo__
---
2017-10-21 12:56:01 +00:00
- Testing has made me a better developer
- Testing can produce better quality code
2017-11-22 23:58:12 +00:00
- Use the right type of test for the right situation
2017-10-21 12:56:01 +00:00
- 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.
^ 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
---
2017-11-08 06:56:37 +00:00
- https://github.com/opdavies/tdd_dublin
2017-11-22 23:58:12 +00:00
- https://www.oliverdavies.uk/blog/2017/11/07/writing-drupal-module-test-driven-development-tdd
- https://www.oliverdavies.uk/blog/tdd-drupal-part-2-kernel-tests
- https://knpuniversity.com/screencast/phpunit
- https://adamwathan.me/test-driven-laravel
- https://laracasts.com
- https://drupalize.me/series/testing-drupal-7-simpletest
- https://www.lullabot.com/articles/an-overview-of-testing-in-drupal-8
- https://www.youtube.com/watch?v=jcdEp3YGa94
2017-11-08 06:56:37 +00:00
---
2017-11-22 23:58:12 +00:00
## __Questions?__