How to get started with writing tests for contrib

Brent Gees

Slides + example module

Who am I?

Who am I?

  • Brent
  • Developer / Architect
  • @brentgees

Who are you?

What is testing

Software testing is a process used to identify the correctness, completeness, and quality of a developed computer software.

It includes a set of activities conducted with the intent of finding errors in software so that it could be corrected before the product is released to the end user

“In simple words, software testing is an activity to check that the software is defect free”

Why this session

Why this session?

  • The first sprint for me was testing
  • You'll learn a lot of new things
  • Really helpful and enough issues
  • You don't have to know the complete module

Own modules vs other modules

Own modules

  • Easy tests are still available
  • You'll have to set up everything yourself

Other modules

  • Will have a lot of functions already created
  • Easy parts will be gone most likely
  • Best if you can find a maintainer
  • 2000 tagged with 'needs tests' in core
  • 4000 tagged with 'needs tests' overall

Why you should write tests

The China airline Airbus A300 crashed due to a software bug in 1994 killing 264 people.

Software bug caused the failure of a military satellite launch, causing a loss of $1.2 billion

responsibility

When your module / patch is used by multiple people, you should make sure that it will work with every update, otherwise you'll break other peoples websites.

  • Manual testing
  • Automated testing​
    • Unit testing
    • Kernel testing
    • Functional testing

Types of testing

Manual testing

Manual testing

  • Done by developer, tester, client and/or project manager
  • Most primitive of all testing types
  • Mostly used for short-term projects
  • Easy to forget use cases
  • Doesn't require a lot of time
  • Becomes very boring if you have to execute the same test multiple times.

Manual testing

  • In the browser
  • With xdebug, var_dump, dsm, dpm, kint
  • Reading code

Manual testing

https://www.drupal.org/project/issues?projects=&status=8

Unit testing

Unit testing

  • Tests on functions, methods, classes
  • Extends on the class UnitTestCase

Advantages of unit testing

  • Verify individual parts
  • Quickly find problems in code
  • Fast execution
  • No system setup for the test run

Disadvantages of unit testing

  • Refactoring your code might require tests to be rewritten
  • Complicated mocking
  • No guarantee that the whole system actually works

Folder structure

../modules/custom
--lissabon
----lissabon.info.yml
----lissabon.module
----src
------Lissabon.php
----tests
------src
--------Unit
----------LissabonSumTest.php

Lissabon.php

<?php

namespace Drupal\lissabon;

/**
 * Defines a Lissabon class.
 */
class Lissabon {
  private $total = 0;

  /**
   * Returns the total amount.
   *
   * @return int
   *   Returns the total
   */
  public function getTotal() {
    return $this->total;
  }

  /**
   * Sets the total.
   *
   * @param int $amount
   *   Amount to be set.
   */
  public function setTotal($amount) {
    $this->total = $amount;
  }

  /**
   * Adds an amount to the total.
   *
   * @param int $amount
   *   Amount to be added.
   */
  public function addToTotal($amount) {
    $this->total = $this->getTotal() + $amount;
  }

}

LissabonSumTest.php

<?php

namespace Drupal\lissabon;

use Drupal\Tests\UnitTestCase;

/**
 * Defines a Unit class.
 *
 * @group lissabon
 */
class LissabonSumTest extends UnitTestCase {
  protected $lissabon;

  /**
   * Before a test method is run, setUp() is invoked.
   *
   * We create a new object of the class Lissabon.
   */
  public function setUp() {
    $this->lissabon = new Lissabon();
  }

}

LissabonSumTest.php

<?php

namespace Drupal\lissabon;

use Drupal\Tests\UnitTestCase;

/**
 * Defines a Unit class.
 *
 * @group lissabon
 */
class LissabonSumTest extends UnitTestCase {

  /**
   * We unset the lissabon object.
   *
   *  Once test method has finished running, whether it succeeded or
   *  failed, tearDown() will be invoked.
   */
  public function tearDown() {
    unset($this->lissabon);
  }

}

LissabonSumTest.php

<?php

namespace Drupal\lissabon;

use Drupal\Tests\UnitTestCase;

/**
 * Defines a Unit class.
 *
 * @group lissabon
 */
class LissabonSumTest extends UnitTestCase {

  /**
   * Covers setTotal.
   */
  public function testSetTotal() {
    $this->assertEquals('0', $this->lissabon->getTotal());
    $this->lissabon->setTotal(366);
    $this->assertEquals(366, $this->lissabon->getTotal());
  }

  /**
   * Covers getTotal.
   */
  public function testGetTotal() {
    $this->lissabon->setTotal(366);
    $this->assertNotEquals(200, $this->lissabon->getTotal());
  }

  /**
   * Covers addToTotal.
   */
  public function testAddToTotal() {
    $this->lissabon->setTotal(200);
    $this->lissabon->addToTotal(166);
    $this->assertEquals(366, $this->lissabon->getTotal());
  }

}

Setting it up for the first time

# Download a drupal installation file (you can also use git clone here)
composer create-project drupal-composer/drupal-project:8.x-dev lissabon-testing
--stability dev --no-interaction --prefer-source


# Install the module you're working on (unless you're working on core,
# here you can alsou use git clone if you want)
composer require drupal/example --prefer-source


# go to the core folder in the web directory
cd lissabon-testing/web/core

# Copy the phpunit.xml.dist file to phpunit.xml
cp phpunit.xml.dist phpunit.xml

Now to the testing part

# Go to the root of your website (web folder)
cd ..

# start the test (change example for the module you're using or leave it empty to test core)
../vendor/bin/phpunit -c core modules/example


# If you want to test 1 specific test, you can add the following option
--filter testName

In action

../vendor/bin/phpunit modules/custom/lissabon/tests/src/Unit/

Looks like it's not working yet

In action

../vendor/bin/phpunit -c core modules/custom/lissabon/tests/src/Unit/

In action

#or, go into the core folder
cd core
../../vendor/bin/phpunit ../modules/custom/lissabon/tests/src/Unit/

Kernel testing

Kernel testing

Kernel tests are integration tests that test on components.
You can install modules

Minimal Drupal, full api, without http


Extends from KernelTestBase or EntityKernelTestBase