Add 'Test Driven Drupal' slides

This commit is contained in:
Oliver Davies 2021-01-05 11:22:16 +00:00
parent 64dc136483
commit 6cf5e862ad
14 changed files with 576 additions and 0 deletions

View file

@ -0,0 +1,4 @@
TDD: Test Driven Drupal
#######################
https://www.oliverdavies.uk/talks/tdd-test-driven-drupal

View file

@ -0,0 +1,13 @@
// web/modules/custom/example/tests/src/Functional.
namespace Drupal\Tests\example\Functional;
use Drupal\Tests\BrowserTestBase;
class ExampleTest extends BrowserTestBase {
public function testSomething() {
$this->assertTrue(FALSE);
}
}

View file

@ -0,0 +1,6 @@
public function testSomething()
public function test_something()
/** @test */
public function it_does_something()

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

View file

@ -0,0 +1,122 @@
pageSetup:
firstTemplate: coverPage
height: 18cm
margin-bottom: 0cm
margin-gutter: 0cm
margin-left: 0cm
margin-right: 0cm
margin-top: 0cm
size: null
spacing-footer: 2mm
spacing-header: 2mm
width: 32cm
pageTemplates:
coverPage:
background: images/title.png
frames: []
[12%, 10%, 76%, 75%]
showFooter: false
showHeader: false
titlePage:
alignment: TA_CENTER
frames: []
[8%, 3%, 85%, 65%]
showFooter: true
showHeader: false
standardPage:
frames: []
[3%, 3%, 92%, 92%]
showFooter: true
showHeader: false
imagePage:
alignment: TA_CENTER
frames: []
[12%, 10%, 76%, 80%]
showFooter: true
showHeader: false
outputPage:
frames: []
[8%, 10%, 82%, 65%]
showFooter: false
showHeader: false
linkColor: #24608a
styles:
normal:
fontSize: 24
leading: 32
textColor: #383745
bodytext:
alignment: TA_LEFT
heading:
fontSize: 20
spaceAfter: 16
textColor: #24608a
title:
fontSize: 300%
parent: heading
textColor: white
bullet-list:
commands: []
[LEFTPADDING, [0, 0], [1, -1], 10]
[RIGHTPADDING, [0, 0], [1, -1], 0]
[VALIGN, [0, 0], [-1, -1], TOP]
colWidths: ["20", null]
textColor: #aaaaaa
bullet-list-item:
spaceBefore: 14
spaceAfter: 0
titleslideinfo:
alignment: TA_CENTER
fontSize: 140%
parent: normal
textColor: #cccccc
footer:
alignment: TA_RIGHT
fontName: stdMono
fontSize: 20
textColor: #24608a
rightIndent: 16
spaceBefore: 0
literal:
backColor: #eeeeee
fontName: stdMono
code:
backColor: #eeeeee
borderWidth: 0
fontSize: 20
leading: 24
parent: literal
spaceBefore: 4
blockquote:
parent: normal
fontName: stdItalic
leading: 36
attribution:
parent: normal
textColor: #66666
centredtitle:
alignment: TA_CENTER
fontName: stdBold
fontSize: 48
leading: 64
parent: heading

View file

@ -0,0 +1,431 @@
.. footer:: @opdavies
TDD: Test Driven Drupal
#######################
|
.. class:: titleslideinfo
Oliver Davies, Inviqa
.. page:: titlePage
.. class:: centredtitle
Software Engineer, open-source maintainer and contributor
.. raw:: pdf
TextAnnotation "I develop Drupal applications for clients, including custom modules and themes."
TextAnnotation "I contribute to open source projects including Drupal core."
TextAnnotation "Different perspectives."
.. page:: imagePage
.. image:: images/timmillwood-ono.png
:width: 22cm
.. raw:: pdf
TextAnnotation "Become maintainer in 2012"
TextAnnotation "~223 most used module on Drupal.org"
TextAnnotation "~30,000 sites - ~20,000 D7 and ~10,000 D8/9"
TextAnnotation "Had some existing tests, crucial to preventing regressions"
.. page:: imagePage
.. image:: images/override-node-options-2012-4.png
:width: 18cm
.. page::
.. image:: images/override-node-options-2020-2.png
:width: 22cm
.. page:: standardPage
Why write tests?
================
* Peace of mind
* Prevent regressions
* Catch bugs earlier
* Write less code
* Documentation
* Drupal core requirement
* More important with regular D8/D9 releases and supporting multiple versions
.. raw:: pdf
TextAnnotation "I don't want to break 30,000 Drupal sites when rolling a new release, or causing a regression in a client codebase."
TextAnnotation "TDD often results in writing less code as you're figuring things out whilst writing the test, only writing code that's needed for the tests."
TextAnnotation "Drupal core gates. Testing gate requires new tests for new features, failing test cases for bug fixes, and code coverage when refactoring code."
TextAnnotation "Same projects can work for Drupal 8 and 9, and in theory 10."
Testing in Drupal
=================
* **Drupal 7** - SimpleTest (testing) module provided as part of core
* **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
Writing Tests (Drupal 8/9)
==========================
* 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
.. raw:: pdf
TextAnnotation "PSR-4 autoloading."
TextAnnotation "Different to D7."
.. page:: titlePage
.. class:: centredtitle
Arrange, Act, Assert
.. page::
.. class:: centredtitle
Given, When, Then
.. raw:: pdf
TextAnnotation "Given the About page exists..."
TextAnnotation "When I go to that page..."
TextAnnotation "I should see 'About me' on the page."
.. page:: standardPage
What to test?
=============
* Creating nodes with data from an API
* Calculating attendance figures for an event
* Determining if an event is purchasable
* Promotions and coupons for new users
* Cloning events
* Queuing private message requests
* Re-opening closed support tickets when comments are added
.. raw:: pdf
TextAnnotation "Examples of some things that I tested on a previous project."
.. page:: imagePage
.. image:: images/matt-stauffer-tweet.png
:width: 20cm
.. page:: standardPage
What does a test look like?
===========================
.. code-block:: php
:include: code/1-example-test.txt
:linenos:
:startinline: true
Writing test methods
====================
.. code-block:: php
:include: code/2-test-methods.txt
:linenos:
:startinline: true
Types of Tests
==============
* **Functional/FunctionalJavascript** (web, browser, feature)
* **Kernel** (integration)
* **Unit**
Functional Tests
================
* Tests end-to-end functionality
* UI testing
* Interacts with database
* Full Drupal installation
* Slower to run
* With/without JavaScript
Kernel tests
============
* Integration tests
* Can install modules, interact with services, container, database
* Minimal Drupal bootstrap
* Faster than functional tests
* More setup required
.. raw:: pdf
TextAnnotation "Can still access services like \Drupal::messenger()."
Unit Tests
==========
* Tests PHP logic
* No database interaction
* Fast to run
* Need to mock dependencies
* Can become tightly coupled
* Can be hard to refactor
.. page:: titlePage
.. class:: centredtitle
Running Tests
.. page:: standardPage
Core script
===========
.. code-block:: shell
$ php core/scripts/run-tests.sh
$ php core/scripts/run-tests.sh --module example
$ php core/scripts/run-tests.sh --class ExampleTest
PHPUnit
=======
.. code-block:: shell
$ vendor/bin/phpunit \
-c core \
modules/contrib/examples/phpunit_example
.. raw:: pdf
TextAnnotation "Update the phpunit path and config file path for your project."
TextAnnotation "-c not needed if the phpunit.xml.dist or phpunit.xml is in the same directory."
Creating a phpunit.xml file
===========================
- Configures PHPUnit
- Needed to run some types of tests
- Ignored by Git by default
- Copy ``core/phpunit.xml.dist`` to ``core/phpunit.xml``
- Add and change as needed
- ``SIMPLETEST_BASE_URL``, ``SIMPLETEST_DB``, ``BROWSERTEST_OUTPUT_DIRECTORY``
- ``stopOnFailure="true"``
.. page:: titlePage
.. class:: centredtitle
Example
.. page:: imagePage
.. image:: images/broadbean-website.png
:width: 20cm
.. page:: standardPage
Specification
=============
* Job adverts created in Broadbean UI, create nodes in Drupal.
* Application URL links users to separate application system.
* Constructed from domain, includes role ID as a GET parameter and optionally UTM parameters.
* Jobs need to be linked to offices.
* Job length specified in number of days.
* Path is specified as a field in the API.
.. raw:: pdf
TextAnnotation "Jobs added to a different system by the client, data POSTed to Drupal."
TextAnnotation "Job applicants would visit the job on the Drupal site, click the application URL and go to another (CRM) system to apply."
TextAnnotation "Client wanted to be able to specify the Drupal path in advance."
.. page:: imagePage
.. image:: images/broadbean-drupal-flow-2.png
:width: 20cm
.. page:: standardPage
Implementation
==============
* Added route to accept data from API as XML
* Added system user with API role to authenticate
* ``active_for`` converted from number of days to UNIX timestamp
* ``branch_name`` and ``locations`` converted from plain text to entity reference (job node to office node)
* ``url_alias`` property mapped to ``path``
.. raw:: pdf
TextAnnotation "Required field missing."
TextAnnotation "Incorrect branch name."
Incoming data
=============
.. code-block:: php
: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',
// ...
];
.. raw:: pdf
TextAnnotation "Some pf the information sent to our endpoint."
Implementation
==============
* If no error, create the job node, return OK response to Broadbean
* If an Exception is thrown, return an error code and message
.. raw:: pdf
TextAnnotation "Required field missing."
TextAnnotation "Branch name incorrect, Exception caught."
Types of tests
==============
* **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)
* **Kernel**: job nodes can be added and deleted, expired job nodes are deleted, application URL is generated correctly
* **Unit**: ensure number of days are converted to timestamps correctly
Results
=======
* 0 bugs!
* Easier to identify where issues occurred and responsibilities
* Reduced debugging time
* Added more tests for any bugs to prevent regressions
.. raw:: pdf
TextAnnotation "Best case scenario."
TextAnnotation "Just because there are tests, it doesn't mean that everything works and everything's passing - just the tests that you wrote are passing."
Test Driven Development
=======================
* Write a failing test
* Write code until the test passes
* Refactor
* Repeat
.. raw:: pdf
TextAnnotation "Write enough of a test so that it fails."
TextAnnotation "Write enough code so that the test passes."
TextAnnotation "Refactor if needed."
TextAnnotation "Repeat."
.. page:: titlePage
.. class:: centredtitle
Red, Green, Refactor
.. page:: standardPage
Porting Modules to Drupal 8
===========================
- Make a new branch
- Add/update the tests
- Write code to make the tests pass
- Refactor
- Repeat
.. raw:: pdf
TextAnnotation "Similar to the TDD workflow."
How I Write Tests - "Outside In"
================================
- 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
- Sometimes write assertions first
.. raw:: pdf
TextAnnotation "Write the code in your test that you wish you had, and let the tests tell you what's missing."
.. page:: titlePage
.. class:: centredtitle
Demo: Building a blog module
.. page:: standardPage
Acceptance criteria
===================
- As a site visitor
- I want to see a list of published articles at ``/blog``
- Ordered by post date, most recent first
Tasks
=====
- Ensure the blog page exists
- Ensure only published articles are shown
- Ensure the articles are shown in the correct order
.. page:: imagePage
.. image:: images/tawny-tweet-1.png
:width: 16cm
.. image:: images/tawny-tweet-2.png
:width: 18cm
.. page:: standardPage
Thanks!
=======
References:
* https://opdavi.es/testing-workshop
* https://testdrivendrupal.com
|
Me:
* https://www.oliverdavies.uk