Update Test Driven Drupal for DrupalCamp Ghent

This commit is contained in:
Oliver Davies 2024-05-09 13:57:56 +01:00
parent 7fdeffb1af
commit 179e27f1b7
12 changed files with 695 additions and 138 deletions

View file

@ -1,6 +1,6 @@
<?php
// start code
// start code 1
namespace Drupal\drupalcon\Repository;
use Drupal\Core\Entity\EntityStorageInterface;
@ -14,16 +14,15 @@ final class ArticleRepository {
private EntityTypeManagerInterface $entityTypeManager,
) {
$this->nodeStorage = $this->entityTypeManager->getStorage('node');
}
} // end code 1
// start code 2
public function getAll(): array {
return $this->nodeStorage->loadMultiple();
}
}
// end code
// end code 2
---

View file

@ -1,10 +1,17 @@
// start services
// start services1
# drupalcon.services.yml
services:
Drupal\drupalcon\Repository\ArticleRepository:
autowire: true
// end services
// end services1
// start services2
services:
Drupal\drupalcon\Repository\ArticleRepository:
arguments:
- '@entity_type.manager'
// end services2
---

View file

@ -1,5 +1,5 @@
public function only_published_articles_are_returned() {
// start test
public function only_published_articles_are_returned() {
$this->createNode(['type' => 'article', 'status' => Node::PUBLISHED]);
$this->createNode(['type' => 'article', 'status' => Node::NOT_PUBLISHED]);
$this->createNode(['type' => 'article', 'status' => Node::PUBLISHED]);
@ -11,8 +11,7 @@ public function only_published_articles_are_returned() {
$articles = $repository->getAll();
$this->assertCount(3, $articles);
// end test
}
} // end test
---

View file

@ -1,5 +1,5 @@
public function nodes_are_ordered_by_date_and_returned_newest_first(): void {
// start test
public function nodes_are_ordered_by_date_and_returned_newest_first(): void {
$this->createNode(['type' => 'article',
'created' => (new DrupalDateTime('-2 days'))->getTimestamp()]);
$this->createNode(['type' => 'article',

View file

@ -18,8 +18,8 @@ final class ArticleRepository {
$this->nodeStorage = $this->entityTypeManager->getStorage('node');
}
public function getAll(): array {
// start code
public function getAll(): array {
$articles = $this->nodeStorage->loadByProperties([
'status' => NodeInterface::PUBLISHED,
]);
@ -28,8 +28,7 @@ final class ArticleRepository {
$b->getCreatedTime() <=> $a->getCreatedTime());
return $articles;
// end code
}
} // end code
}

View file

@ -3,7 +3,9 @@
namespace Drupal\drupalcon\Controller;
class BlogPageController {
declare(strict_types=1);
final class BlogPageController {
public function __invoke(): array {
return [];

View file

@ -11,6 +11,27 @@ public function it_loads_the_blog_page(): void {
}
// end test
E 1 / 1 (100%)
Time: 00:02.101, Memory: 6.00 MB
// start output
There was 1 error:
1) Drupal\Tests\drupalcon\Functional\BlogPageTest::it_loads_the_blog_page
Behat\Mink\Exception\ResponseTextException:
The text "Welcome to my blog!" was not found anywhere in the text
of the current page.
// end output
/app/vendor/behat/mink/src/WebAssert.php:907
/app/vendor/behat/mink/src/WebAssert.php:293
/app/web/modules/custom/drupalcon/tests/src/Functional/BlogPageTest.php:17
/app/vendor/phpunit/phpunit/src/Framework/TestResult.php:728
ERRORS!
Tests: 1, Assertions: 3, Errors: 1.
// start code
namespace Drupal\drupalcon\Controller;
@ -29,12 +50,12 @@ class BlogPageController {
}
// end code
// start output
// start output2
. 1 / 1 (100%)
Time: 00:01.911, Memory: 6.00 MB
OK (1 test, 3 assertions)
// end output
// end output2
Task completed in 0m2.124s

View file

@ -11,11 +11,8 @@ class ArticleRepositoryTest extends EntityKernelTestBase {
public function it_returns_blog_posts(): void {
$repository = $this->container->get(ArticleRepository::class);
$articles = $repository->getAll();
$this->assertCount(1, $articles);
}
// end code
$this->assertCount(1, $repository->getAll());
}// end code
}

View file

@ -1,8 +1,11 @@
..
This file used a mixture of `plain` and `php` languages for code blocks so that `hl_lines` display correctly.
.. page:: titlePage
.. class:: centredtitle
Demo: Building a blog module
Building a blog module
.. raw:: pdf
@ -30,43 +33,141 @@ Tasks
.. Creating the test class.
.. code-block:: php
:include: code/2.txt
:linenos:
:startinline: true
:include: code/2.txt
:linenos:
:startinline: true
.. raw:: pdf
PageBreak
.. code-block:: php
:include: code/2.txt
:linenos:
:startinline: true
:hl_lines: 1,2,3
.. raw:: pdf
PageBreak
.. code-block:: php
:include: code/2.txt
:linenos:
:startinline: true
:hl_lines: 5,6,7
.. raw:: pdf
PageBreak
.. code-block:: php
:include: code/2.txt
:linenos:
:startinline: true
:hl_lines: 9,10,11
.. page::
.. Adding the first test.
.. code-block:: php
:end-before: // end test
:include: code/3.txt
:linenos:
:startinline: true
:end-before: // end test
.. raw:: pdf
PageBreak
.. code-block:: php
:include: code/3.txt
:linenos:
:startinline: true
:end-before: // end test
:hl_lines: 3,4,8
.. raw:: pdf
PageBreak
.. code-block:: php
:include: code/3.txt
:linenos:
:startinline: true
:end-before: // end test
:hl_lines: 5
.. raw:: pdf
PageBreak
.. code-block:: php
:include: code/3.txt
:linenos:
:startinline: true
:end-before: // end test
:hl_lines: 7
.. page::
.. code-block:: plain
:end-before: // end output
:include: code/3.txt
:start-after: // start output
:startinline: true
:include: code/3.txt
:startinline: true
:start-after: // start output
:end-before: // end output
.. code-block:: php
:include: code/3.txt
:startinline: true
:start-after: // start output
:end-before: // end output
:hl_lines: 1,5
.. code-block:: php
:include: code/3.txt
:startinline: true
:start-after: // start output
:end-before: // end output
:hl_lines: 7
.. code-block:: php
:include: code/3.txt
:startinline: true
:start-after: // start output
:end-before: // end output
:hl_lines: 8,9
.. page::
.. code-block:: yaml
:end-before: // end routing
:include: code/3.txt
:linenos:
:start-after: // start routing
:end-before: // end routing
.. page::
.. code-block:: plain
:end-before: // end output
.. code-block:: yaml
:include: code/3.txt
:linenos:
:start-after: // start routing
:end-before: // end routing
:hl_lines: 4,6
.. raw:: pdf
TextAnnotation "This controller doesn't exist yet, but the test will tell us that."
.. page::
.. code-block:: php
:include: code/3.txt
:start-after: // start output
:startinline: true
:start-after: // start output
:end-before: // end output
:hl_lines: 7,8,9
.. raw:: pdf
@ -76,262 +177,581 @@ Tasks
.. code-block:: php
:include: code/4.txt
:end-before: // output
:linenos:
:startinline: true
:end-before: // output
|
.. code-block:: plain
:include: code/4.txt
:end-before: // end output
:start-after: // output
:startinline: true
:start-after: // output
:end-before: // end output
.. page::
.. raw:: pdf
TextAnnotation "The `access content` permission isn't available."
PageBreak
.. Enable the node module.
.. code-block:: php
:include: code/5.txt
:linenos:
:end-before: // end code
:startinline: true
:end-before: // end code
|
.. code-block:: php
.. code-block:: plain
:include: code/5.txt
:end-before: // end output
:start-after: // start output
:end-before: // end output
.. page::
.. raw:: pdf
TextAnnotation "The error has changed. This is good."
TextAnnotation "The controller we specified doesn't exist."
PageBreak
.. Create the Controller.
.. code-block:: php
:end-before: // end code
:include: code/6.txt
:linenos:
:startinline: true
:start-after: // start code
.. page::
.. code-block:: plain
:end-before: // end output
:include: code/6.txt
:start-after: // start output
.. page::
.. code-block:: php
:end-before: // end test
:include: code/7.txt
:linenos:
:startinline: true
:start-after: // start test
:end-before: // end code
.. raw:: pdf
TextAnnotation "Adding extra assertions."
PageBreak
.. code-block:: php
:include: code/6.txt
:linenos:
:startinline: true
:start-after: // start code
:end-before: // end code
:hl_lines: 1,2,3
.. page::
.. code-block:: php
:end-before: // end code
:include: code/7.txt
:include: code/6.txt
:linenos:
:startinline: true
:start-after: // start code
:end-before: // end code
:hl_lines: 7,13
.. page::
.. code-block:: php
:include: code/6.txt
:linenos:
:startinline: true
:start-after: // start code
:end-before: // end code
:hl_lines: 9,10,11
.. page::
.. code-block:: plain
:include: code/6.txt
:start-after: // start output
:end-before: // end output
.. page::
.. code-block:: php
:include: code/7.txt
:linenos:
:startinline: true
:start-after: // start test
:end-before: // end test
.. raw:: pdf
TextAnnotation "Adding more assertions."
PageBreak
.. code-block:: php
:include: code/7.txt
:linenos:
:startinline: true
:start-after: // start test
:end-before: // end test
:hl_lines: 5,6
.. raw:: pdf
TextAnnotation "Refactor the original assertion."
PageBreak
.. code-block:: php
:include: code/7.txt
:linenos:
:startinline: true
:start-after: // start test
:end-before: // end test
:hl_lines: 8,9
.. page::
.. code-block:: plain
:include: code/7.txt
:start-after: // start output
:end-before: // end output
.. page::
.. code-block:: php
:end-before: // end code
:include: code/8.txt
:include: code/7.txt
:linenos:
:start-after: // start code
:startinline: true
:start-after: // start code
:end-before: // end code
:hl_lines: 3,7
.. page::
.. code-block:: php
:include: code/7.txt
:linenos:
:startinline: true
:start-after: // start code
:end-before: // end code
:hl_lines: 10,11,12
.. page::
.. code-block:: plain
:include: code/7.txt
:start-after: // start output2
:end-before: // end output2
.. page::
.. code-block:: php
:include: code/8.txt
:linenos:
:startinline: true
:start-after: // start code
:end-before: // end code
.. page::
.. code-block:: php
:include: code/8.txt
:linenos:
:startinline: true
:start-after: // start code
:end-before: // end code
:hl_lines: 1,2,3,4,5,6,7,15
.. page::
.. code-block:: php
:include: code/8.txt
:linenos:
:startinline: true
:start-after: // start code
:end-before: // end code
:hl_lines: 9,10,14
.. page::
.. code-block:: php
:include: code/8.txt
:linenos:
:startinline: true
:start-after: // start code
:end-before: // end code
:hl_lines: 11
.. page::
.. code-block:: php
:include: code/8.txt
:linenos:
:startinline: true
:start-after: // start code
:end-before: // end code
:hl_lines: 13
.. page::
.. code-block:: php
:end-before: // end output
:include: code/8.txt
:start-after: // start output
:end-before: // end output
.. code-block:: php
:include: code/8.txt
:start-after: // start output
:end-before: // end output
.. page::
.. code-block:: php
:end-before: // end code
:include: code/9.txt
:linenos:
:start-after: // start code
:startinline: true
:start-after: // start code
:end-before: // end code
|
.. code-block:: yaml
:end-before: // end services
:include: code/9.txt
:linenos:
:start-after: // start services
:end-before: // end services
.. page::
.. code-block:: yaml
:end-before: // end output
:include: code/9.txt
:start-after: // start output
:end-before: // end output
.. page::
.. code-block:: php
:end-before: // end code
:include: code/10.txt
:linenos:
:start-after: // start code
:startinline: true
:start-after: // start code
:end-before: // end code
:hl_lines: 5,6,7
.. page::
.. code-block:: plain
:end-before: // end output
:include: code/10.txt
:start-after: // start output
:end-before: // end output
.. page::
.. code-block:: php
:end-before: // end code
:include: code/11.txt
:linenos:
:startinline: true
:start-after: // start code
:start-after: // start code 1
:end-before: // end code 1
.. page::
.. code-block:: php
:include: code/11.txt
:linenos:
:startinline: true
:start-after: // start code 1
:end-before: // end code 1
:hl_lines: 10,11,12
.. page::
.. code-block:: php
:include: code/11.txt
:linenos:
:startinline: true
:start-after: // start code 1
:end-before: // end code 1
:hl_lines: 8,13
.. page::
.. code-block:: php
:include: code/11.txt
:linenos:
:startinline: true
:start-after: // start code 2
:end-before: // end code 2
:hl_lines: 1,3
.. page::
.. code-block:: php
:include: code/11.txt
:linenos:
:startinline: true
:start-after: // start code 2
:end-before: // end code 2
:hl_lines: 2
.. page::
.. code-block:: yaml
:end-before: // end services
:include: code/12.txt
:linenos:
:start-after: // start services
:start-after: // start services1
:end-before: // end services1
|
.. code-block:: yaml
:include: code/12.txt
:linenos:
:start-after: // start services2
:end-before: // end services2
.. raw:: pdf
TextAnnotation "Declare the Repository as a service."
TextAnnotation "Autowire or declare dependencies explicitly."
.. page::
.. code-block:: plain
:end-before: // end output
:include: code/12.txt
:start-after: // start output
:end-before: // end output
|
.. code-block:: php
:end-before: // end test
:include: code/13.txt
:linenos:
:start-after: // start test
:startinline: true
:start-after: // start test
:end-before: // end test
.. page::
.. code-block:: plain
:end-before: // end output
:include: code/13.txt
:start-after: // start output
:end-before: // end output
.. page::
.. code-block:: php
:end-before: // end test
:include: code/14.txt
:linenos:
:start-after: // start test
:startinline: true
:start-after: // start test
:end-before: // end test
:hl_lines: 1
.. page::
.. code-block:: php
:include: code/14.txt
:linenos:
:startinline: true
:start-after: // start test
:end-before: // end test
:hl_lines: 5
.. page::
.. code-block:: plain
:end-before: // end output
:include: code/14.txt
:start-after: // start output
:end-before: // end output
.. page::
.. code-block:: php
:end-before: // end test
:include: code/15.txt
:linenos:
:start-after: // start test
:end-before: // end test
:startinline: true
.. raw:: pdf
TextAnnotation "We know we're getting a node, but are we getting the correct node?"
PageBreak
.. code-block:: php
:include: code/15.txt
:linenos:
:startinline: true
:start-after: // start test
:end-before: // end test
:hl_lines: 1,2,3,4
.. raw:: pdf
TextAnnotation "Create a node with a specific title."
PageBreak
.. code-block:: php
:include: code/15.txt
:linenos:
:startinline: true
:end-before: // end test
:start-after: // start test
:hl_lines: 10,11
.. page::
.. code-block:: php
:end-before: // end test
:include: code/16.txt
:include: code/15.txt
:startinline: true
:linenos:
:start-after: // start test
:startinline: true
:end-before: // end test
:hl_lines: 13,14,15
.. page::
.. raw:: pdf
.. code-block:: plain
:end-before: // end output
TextAnnotation "Ensure the node is an article and has the correct title."
PageBreak
.. Published or unpublished nodes.
.. code-block:: php
:include: code/16.txt
:start-after: // start output
:linenos:
:startinline: true
:start-after: // start test
:end-before: // end test
.. page::
.. code-block:: php
:include: code/16.txt
:linenos:
:startinline: true
:start-after: // start test
:end-before: // end test
:hl_lines: 2,4,6
.. page::
.. code-block:: php
:include: code/16.txt
:linenos:
:startinline: true
:start-after: // start test
:end-before: // end test
:hl_lines: 3,5
.. page::
.. code-block:: php
:include: code/16.txt
:linenos:
:startinline: true
:start-after: // start test
:end-before: // end test
:hl_lines: 12
.. raw:: pdf
TextAnnotation "We should only have three published articles."
PageBreak
.. code-block:: plain
:include: code/16.txt
:start-after: // start output
:end-before: // end output
.. page::
.. code-block:: php
:end-before: // end code
:include: code/17.txt
:linenos:
:start-after: // start code
:startinline: true
:start-after: // start code
:end-before: // end code
|
.. code-block:: plain
:end-before: // end output
:include: code/17.txt
:start-after: // start output
:end-before: // end output
.. page::
.. Ensure articles are ordered correctly.
.. code-block:: php
:end-before: // end test
:include: code/18.txt
:linenos:
:startinline: true
:start-after: // start test
:startinline: true
.. page::
.. code-block:: plain
:end-before: // end output
:include: code/18.txt
:start-after: // start output
:end-before: // end test
.. page::
.. code-block:: php
:end-before: // end code
:include: code/19.txt
:include: code/18.txt
:linenos:
:start-after: // start code
:startinline: true
:start-after: // start test
:end-before: // end test
:hl_lines: 3,5,7,9,11
|
.. page::
.. code-block:: php
:include: code/18.txt
:linenos:
:startinline: true
:start-after: // start test
:end-before: // end test
:hl_lines: 16
.. page::
.. code-block:: plain
:include: code/18.txt
:start-after: // start output
:end-before: // end output
.. page::
.. code-block:: php
:include: code/19.txt
:linenos:
:startinline: true
:start-after: // start code
:end-before: // end code
.. page::
.. code-block:: php
:include: code/19.txt
:linenos:
:startinline: true
:start-after: // start code
:end-before: // end code
:hl_lines: 2,3,4
.. page::
.. code-block:: php
:include: code/19.txt
:linenos:
:startinline: true
:start-after: // start code
:end-before: // end code
:hl_lines: 6,7
.. raw:: pdf
TextAnnotation "Spaceship operator!"
PageBreak
.. code-block:: php
:include: code/19.txt
:linenos:
:startinline: true
:start-after: // start code
:end-before: // end code
:hl_lines: 9
.. page::
.. code-block:: plain
:include: code/19.txt
:start-after: // start output
:end-before: // end output

View file

@ -55,25 +55,52 @@ Incoming data
=============
.. code-block:: php
:include: example/incoming.txt
:startinline: true
$data = [
'command' => 'add',
'username' => 'bobsmith',
'password' => 'p455w0rd',
'active_for' => '365',
'details' => 'This is the detailed description.',
'job_title' => 'Healthcare Assistant (HCA)',
'locations' => 'Bath, Devizes',
'role_id' => 'A/52/86',
'summary' => 'This is the short description.',
'url_alias' => 'healthcare-assistant-aldershot-june17',
// ...
];
Incoming data
=============
.. code-block:: php
:include: example/incoming.txt
:hl_lines: 2
:startinline: true
Incoming data
=============
.. code-block:: php
:include: example/incoming.txt
:hl_lines: 3, 4
:startinline: true
Incoming data
=============
.. code-block:: php
:include: example/incoming.txt
:hl_lines: 5
:startinline: true
Incoming data
=============
.. code-block:: php
:include: example/incoming.txt
:hl_lines: 6, 7, 8, 9, 10
:startinline: true
Incoming data
=============
.. code-block:: php
:include: example/incoming.txt
:hl_lines: 11
:startinline: true
.. raw:: pdf
TextAnnotation "Some pf the information sent to our endpoint."
TextAnnotation "Some of the information sent to our endpoint."
Implementation
==============

View file

@ -0,0 +1,13 @@
$data = [
'command' => 'add',
'username' => 'bobsmith',
'password' => 'p455w0rd',
'active_for' => '365',
'details' => 'This is the detailed description.',
'job_title' => 'Healthcare Assistant (HCA)',
'locations' => 'Bath, Devizes',
'role_id' => 'A/52/86',
'summary' => 'This is the short description.',
'url_alias' => 'healthcare-assistant-aldershot-june17',
// ...
];

View file

@ -10,20 +10,21 @@ TDD: Test Driven Drupal
Oliver Davies (@opdavies)
|
.. class:: centred
https://opdavi.es/tdd-test-driven-drupal
.. class:: titleslideinfo
https://opdavi.es/dcg
.. page:: titlePage
.. class:: centredtitle
Software Engineer, Full Stack Development Consultant, Open-Source Maintainer
Software Developer, Consultant, open-source maintainer
.. raw:: pdf
TextAnnotation "I develop and consult on Drupal applications for clients."
TextAnnotation "I contribute to and maintain open source projects including Drupal core."
TextAnnotation "I contribute to and maintain open-source projects including Drupal core."
TextAnnotation "Different perspectives."
.. page:: imagePage
@ -33,7 +34,7 @@ Software Engineer, Full Stack Development Consultant, Open-Source Maintainer
.. raw:: pdf
TextAnnotation "Become maintainer in 2012"
TextAnnotation "I saw this tweet by Tim Millwood and become the maintainer in 2012."
.. page:: imagePage
@ -42,6 +43,8 @@ Software Engineer, Full Stack Development Consultant, Open-Source Maintainer
.. page::
TextAnnotation "These were the usage statistics from Drupal.org when I became the maintainer."
|
.. image:: images/override-node-options-2.png
@ -69,7 +72,7 @@ Why write tests?
* Write less code
* Documentation
* Drupal core requirement
* More important with regular D8/D9 releases and supporting multiple versions
* More important with regular D10/D11 releases and supporting multiple versions
.. raw:: pdf
@ -85,12 +88,16 @@ Testing in Drupal
* **Drupal 8** - PHPUnit added as a core dependency, later became the default via the PHPUnit initiative
* **Drupal 9** - SimpleTest removed from core, moved back to contrib
.. raw:: pdf
TextAnnotation "Not speaking about Drupal 7 and SimpleTest in this talk, but a lot of the concepts are the same."
Writing PHPUnit Tests for Drupal
================================
* PHP class with ``.php`` extension
* ``tests/src`` directory within each module
* Within the ``Drupal\Tests\module_name`` namespace
* Within the ``Drupal\Tests\{module_name}`` namespace
* Class name must match the filename
* Namespace must match the directory structure
* One test class per feature
@ -109,6 +116,8 @@ Arrange, Act, Assert
.. raw:: pdf
TextAnnotation "What are the parts of a test?"
TextAnnotation ""
TextAnnotation "Set up the world, perform an action, then make assertions."
.. page::
@ -157,6 +166,42 @@ What does a test look like?
:linenos:
:startinline: true
What does a test look like?
===========================
.. code-block:: php
:include: code/1-example-test.txt
:linenos:
:startinline: true
:hl_lines: 1,2,3,13
What does a test look like?
===========================
.. code-block:: php
:include: code/1-example-test.txt
:linenos:
:startinline: true
:hl_lines: 5,6,7
What does a test look like?
===========================
.. code-block:: php
:include: code/1-example-test.txt
:linenos:
:startinline: true
:hl_lines: 9,11
What does a test look like?
===========================
.. code-block:: php
:include: code/1-example-test.txt
:linenos:
:startinline: true
:hl_lines: 10
Writing test methods
====================
@ -165,6 +210,33 @@ Writing test methods
:linenos:
:startinline: true
Writing test methods
====================
.. code-block:: php
:include: code/2-test-methods.txt
:hl_lines: 1
:linenos:
:startinline: true
Writing test methods
====================
.. code-block:: php
:include: code/2-test-methods.txt
:hl_lines: 3
:linenos:
:startinline: true
Writing test methods
====================
.. code-block:: php
:include: code/2-test-methods.txt
:hl_lines: 5, 6
:linenos:
:startinline: true
Types of Tests
==============
@ -186,6 +258,10 @@ Functional Tests
* Slower to run
* With/without JavaScript
.. raw:: pdf
TextAnnotation "Uses the `testing` profile with a fresh installation between tests."
Kernel tests
============
@ -337,8 +413,8 @@ Red, Green, Refactor
.. page:: standardPage
Porting Modules to Drupal 8
===========================
Porting Modules From Drupal 7
=============================
- Make a new branch
- Add/update the tests
@ -379,9 +455,6 @@ Run in 2-3 minutes in a CI pipeline with GitHub Actions.
.. page:: imagePage
.. image:: images/tawny-tweet-1.png
:width: 16cm
.. image:: images/tawny-tweet-2.png
:width: 18cm