test all the things! automated testing with drupal 8

35

Upload: sam-becker

Post on 13-Apr-2017

308 views

Category:

Technology


4 download

TRANSCRIPT

Test all the things!Automated testing with Drupal 8

27th Oct. 2016

Who am I?

In this session● High level introduction of different testing concepts used in core and contrib● How these concepts can be used to test bespoke Drupal site builds● When to apply different types of tests to different situations

What are tests? Why test your code?● Code that executes code● Asserts a set of constraints● Usually run on regular intervals

● See fewer bugs in production● Make stakeholders (and developers!)

happy● Release and deploy more confidently● Write better code● Refactor more confidently

How do we test code in Drupal 8?● All tools found in Drupal core● All based on PHPUnit● Base classes help with interacting with Drupal

○ UnitTestCase○ KernelTestBase○ BrowserTestBase○ JavascriptTestBase○ … more on these later

● Useful for contrib, core and client projects● Useful outside of Drupal?

PHPUnit

● Testing framework written in PHP● Adopted by many other PHP frameworks

Basic anatomy of a PHPUnit test● Live in the Drupal\Tests\module

namespace● They usually extend a Drupal test base● Setup method is run for every test method● Each test method is prefixed with the word

“test”● A test method contains a series of

assertions● PHPUnit provides lots of assertion

methods

PHPUnit assertionsassertArrayHasKeyassertClassHasAttributeassertArraySubsetassertClassHasStaticAttributeassertContainsassertContainsOnlyassertContainsOnlyInstancesOfassertCountassertDirectoryExistsassertDirectoryIsReadableassertDirectoryIsWritableassertEmptyassertEqualXMLStructureassertEquals

assertFalseassertFileEqualsassertFileExistsassertFileIsReadableassertFileIsWritableassertGreaterThanassertGreaterThanOrEqualassertInfiniteassertInstanceOfassertInternalTypeassertIsReadableassertIsWritable… and others (https://phpunit.de/manual/)

PHPUnit mocking● Create classes your test code depends on● Define exactly how they should behave● Use as much or as little as the

dependency as you like

More on mocking:https://phpunit.de/manual/current/en/test-doubles.html

PHPUnit @dataProvder● Data providers run a test method with lots

of different inputs● Allows you to name you test cases● Helps cover lots of scenarios and quickly

identify what is broken

Running tests● Configure all the environment variables

required to run tests (https://www.drupal.org/docs/8/phpunit/running-phpunit-tests)

● Use the phpunit binary● PHPStorm integration!

UnitTestCase● Drupals unit testing base class● Tests the behavior of a class in isolation● Mock your dependencies, inject them● No access to a Drupal bootstrap or database● Very fast● Test lots of inputs/outputs very quickly

Tests informing design● Testable code is good code● Clearly reveals your dependencies (some you never knew you had)● Illustrates when you might have too many dependencies● Encourages you to expose the minimum amount of information required

between classes

Real world examples

● Very simple unit test with single assertion.

● Simple input/out scenario, not mocking required.

● ~10ms per test case

Reference Table Formatter

List of Content Entities =>

Test doubles required for:

● EntityTypeInterface● FieldDefinitionInterface● FieldItemListInterface● EntityManagerInterface● EntityTypeInterface● EntityStorageInterface● EntityViewDisplayInterface● RendererInterface

● Possibly a sign of bad design, should some of the logic in the module be split into different class?

● Pain to write and maintain, 150 lines of code to mock dependencies.

● Possibly should have been an integration test, testing against real world instances of these dependencies.

Under the hood

There are limits...

KernelTestBase● New concept to Drupal 8● Write test code within a bootstrapped Drupal site● Tests your codes integration with Drupal and other components● Gives you access to Drupal APIs (entities, services, plugins etc)● Still have access to all of the PHPUnit assertions and mocking● Still pretty fast

● Install parts of Drupal required for the test on demand

● Entity schema and module configuration needs to be explicitly installed

● Drupal content and configuration can be created as part of the test

● Creates an entity●● Sets a field value and● calls the view method

Runs through full entity API system.

● ~3s per test case●

● Introduces a web browser● Functional, end-to-end testing, using a UI, simulating a user● Write instructions for the web browser and make assertions about the UI

along the way● Verbose output can show you a snapshot of the page at each step in the

test● Slow to run

BrowserTestBase

Mink● Pluggable browsers, one API● Two browsers used in core (for now)● Brings a whole library of assertions with it● ...more at http://mink.behat.org/

The testing pyramid● Write lots of unit tests● Write integration tests● Write some end-to-end UI tests

● Just a guide, common sense applies!

JavascriptTestBase● BrowserTestBase but with JavaScript!● Same assertion library as BTB● Uses PhantomJS mink plugin● Required for testing any kind of AJAX● Test any JS UI interaction

○ Opening a lightbox○ Scrolling the page○ Resizing your window○ Hovering over a menu

WebKit under the hood

Utility Traits● Add useful functionality to

test classes○ Create test content○ Load entities

○ Custom more specific assertions

● Extend KTB, BTB or JTB and use the same methods.

Cheating setUp● Run tests against a pre-setup site:

https://www.drupal.org/node/2793445

● Useful for functional tests that broadly cover a whole site

● Let CI do the heavy lifting

● WebTestBase, based on simpletest in Drupal 7○ Still lots of core tests being converted

● The other KernelTestBase before it was based on phpunit○ … when KTB was KTBTNG

Deprecated test classes

Consider not writing a test when...● The code isn’t complex● The test will only fails with false positives● It has a maintenance cost with no benefit

Final thoughts● Testing in Drupal 8 is awesome● Write lots of tests

Questions?