drupal con nashville con... · drupal 8: let’s dive into phpunit testing. sugandh khanna srijan,...

60
DRUPAL CON NASHVILLE 2018 DRUPALCON NASHVILLE

Upload: hoanghanh

Post on 15-Feb-2019

223 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

DRUPAL CON

NASHVILLE 2018

DRUPALCON NASHVILLE

Page 2: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

DRUPAL CON

NASHVILLE 2018

Drupal 8: Let’s dive into PHPUnit testing.

Page 3: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Drupal 8: Let’s dive into PHPUnit testing.

Sugandh KhannaSrijan, INDIA

Drupal CON NASHVILLEMarch 2018

Page 4: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

AGENDA

● Automated testing in D8 - History● Type of tests in D8● What is Unit Testing● Why we need unit testing ● What is PHPUnit● Php unit test -Best practices & Thumb rule● A Basic example● How to run test● Assertions & data Providers● Test doubles● Setup() Method● Mock Objects ● Stub Methods

Page 5: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

AUTOMATED TESTING IN DRUPAL - HISTORY

Drupal 6 - Simpletest module

Drupal 7 - Simpletest in core

Drupal 8 -

Simpletest still in core but deprecated (to be removed in D9)

PHPUnit introduced into core

This presentation focuses exclusively on PHPUnit

Page 6: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

TYPES OF TESTS IN DRUPAL 8

Unit tests

Kernel tests

Functional tests

JavaScript functional tests

Page 7: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Types of testing with an oversimplified example:

For a functional mobile phone, the main parts required are “battery” and “sim card”.● Unit testing– the battery is checked for its life,

capacity and other parameters. Sim card is checked for its activation.

● Kernel Testing– battery and sim card are integrated i.e. assembled in order to start the mobile phone.

● Functional Testing– the functionality of the mobile phone is checked in terms of its features and also battery usage as well as sim card facilities.

Page 8: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Exploring Unit testing only...

A unit test, then, is a sanity check to make sure that the chunk of

functionality does what it’s supposed to.

Page 9: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Few important points about unit testing and its benefits:

● Unit testing is done before Integration testing using white box testing techniques.

● Unit testing does not only check the positive behavior but also the failures that occur with invalid input.

● Finding issues/bugs at an early stage is very useful and it reduces the overall project costs.

● A unit test tests small pieces of code or individual functions so the issues/errors found in these test cases are independent and do not impact the other test cases.

● Another important advantage is that the unit test cases simplify and make testing of code easier.

● Unit test saves time and cost, and it is reusable and easy to maintain.

Coming up: why we need unit testing? Importance of unit testing.

Page 10: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Why we need unit testing?

Unit testing any application will not only save you a lot of headaches during development, but it can result in code that’s easier to maintain, allowing you to make more fearless changes (like major refactoring) without hesitation.

Page 11: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Let’s begin...

Page 12: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

What is PHPUnit?

- A unit testing framework written in PHP, created by Sebastian Bergman

- Part of the xUnit family of testing frameworks.- While there are other testing frameworks for PHP

(such as SimpleTest or Atoum) PHPUnit has become the de facto standard.

Page 13: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Best practice for writing PHPUnit

tests

Page 14: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

File structure and filenames● Unit tests go in

[MODULENAME]/tests/src/Unit● Namespace is

Drupal\Tests\[MODULENAME]\Unit

Page 15: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

● Classnames: This should be exactly same as filenames.

● Method (test) names: Our test method names should start with test, in lower case.

● Extends PHPUnit: Classes must extend the class, UnitTestCase or extend a class that does

Page 16: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Thumb rule:Before writing the first test, think about what we need to actually test from the code given.

Page 17: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

<?php

namespace Drupal\vf_hierarchy\Controller;

use Drupal\Core\Controller\ControllerBase;

class HierarchyController extends ControllerBase {

public function dummyFunc() {//}

}

<?php

namespace Drupal\Tests\vf_hierarchy\Unit;

use Drupal\Tests\UnitTestCase;

/** * @group vf_hierarchy */

class HierarchyControllerTest extends UnitTestCase {

public function testDummyFunc() { $foo = true; $this->assertTrue($foo);}

Basic Example

??

Page 18: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

ASSERTIONS

What is an assertion?

Wikipedia defines an assertion as

a predicate (a true–false statement) placed in a program to indicate that the developer thinks that the predicate is always true at that place.

Translated, all it is saying is that an assertion verifies a statement made equals true.

Page 19: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

In order to run this test… Either

1. Enable Testing module.

2. Php core /scripts/run-tests.sh --verbose --url localhost --color vf_hierarchy

Page 20: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018
Page 21: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Processing test 1 0f 1 - Drupal\Tests\vf_hierarchy\Unit\HierarchyControllerTest

Page 22: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018
Page 23: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018
Page 24: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018
Page 25: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018
Page 26: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

What are Test Doubles?

Page 27: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Test doubles (or mock objects) allow to focus a unit test on the code that needs to be tested without bootstrapping dependencies.

Page 28: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

When to use test double?

Page 29: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

It is very common in our code, a function of one class is calling another class's function. In this case, we have a dependency in these two classes. In particular, the caller class has a dependency on calling class. But as we already know, unit test should test the smallest unit of functionality, in this case, it should test only the caller function. To solve this problem, We can use test double to replace the calling class. Since a test double can be configured to return predefined results, we can focus on testing the caller function.

Page 30: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Types of “Test Doubles”

Page 31: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Types of test doubles● Dummy objects are passed around but never actually used. Usually

they are just used to fill parameter lists.● Fake objects actually have working implementations, but usually take

some shortcut which makes them not suitable for production.● Stubs provide canned answers to calls made during the test, usually

not responding at all to anything outside what's programmed in for the test.

● Spies are stubs that also record some information based on how they were called. One form of this might be an email service that records how many messages it was sent.

● Mocks are pre-programmed with expectations which form a specification of the calls they are expected to receive. They can throw an exception if they receive a call they don't expect and are checked during verification to ensure they got all the calls they were expecting.

Page 32: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Setup(), Mock Objects, data Providers and Stub Methods

Page 33: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

<?phpnamespace Drupal\vf_device_models\Controller;use Drupal\Core\Controller\ControllerBase;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\HttpFoundation\JsonResponse;

class DeviceModelController extends ControllerBase {

public function getDeviceModel(Request $request, $id = NULL, $name, $level) { $result = ' ‘; $result = $this->getDeviceModelLists($request, $id, $name, NULL, $level); $response = new JsonResponse($result); If ($response) { return TRUE; } }

Page 34: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Before writing the first test, think about what we need to actually test from the code given.

Check…..

● Weather the function is returning json object or not?

● If there’s is json object, asserts true, else test will fail.

Let’s prepare skelton:

Page 35: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

<?php

namespace Drupal\Tests\vf_device_models\Unit {

use Drupal\vf_device_models\Controller\DeviceModelController; use Drupal\Tests\UnitTestCase;

/** * @group vf_device_models */ class DeviceModelControllerTest extends UnitTestCase { protected $messenger; protected $request;

protected function setUp() { parent::setUp(); $this->messenger = new DeviceModelController(); } public function testgetDeviceModel() { //body of function…….. } }}

??

Page 36: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

PHPUnit: setUp

• The setUp method is executed for every test method in a class.

• Configure fixtures or setting up known state such as database or test files.

• Configure test doubles or mocks, which are dependencies of a unit that you do not need to test in that test class.

protected function setUp() { $this->stack = [];}

Invoked before a test method is run.

Page 37: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

protected function setUp() { parent::setUp(); $this->messenger = new DeviceModelController(); }

public function testgetDeviceModel() { $result = $this->messenger->getDeviceModel($this->request,'1209','sugandh25062','market','514'); $this->assertTrue($this->messenger->getDeviceModel($this->request,'1209','sugandh25062','market','514'), "The json object is created.");}

Page 38: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018
Page 39: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Why this exception?????

Because it requires “Request” instance for the test function to execute. Since unit testing means test in isolation, so the need of the hour is to create a

fake object of class Request.

MOCK

Page 40: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

protected function setUp() { parent::setUp();

$this->request = $this->getMockBuilder('\Symfony\Component\HttpFoundation\Request') ->disableOriginalConstructor() ->setMethods([ ]) ->getMock();

$this->messenger = new DeviceModelController($this->request);}

Page 41: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018
Page 42: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Happy!

First test run success…. :D

Page 43: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

So understood Mocks?

Or need 1 more example?

Let’s have one more example from core:(Function checks whether user is authenticated or not.. If yes, returns uid.)

Page 44: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

public function authenticate($username, $password) {

$uid = FALSE;

if (!empty($username) && strlen($password) > 0) {

$account_search = $this->entityManager->getStorage('user')->loadByProperties(['name' => $username]);

..... }

return $uid; }

Page 45: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

/** * @dataProvider providerTestAuthenticateWithMissingCredentials */ public function testAuthenticateWithMissingCredentials($username, $password) { $this->userStorage->expects($this->never()) ->method('loadByProperties');

$this->assertFalse($this->userAuth->authenticate($username, $password)); }

/** * Data provider for testAuthenticateWithMissingCredentials(). */ public function providerTestAuthenticateWithMissingCredentials() { return [ [NULL, NULL], [NULL, ''], ['', NULL], ['', ''], ]; }

Data providers .. ??

Page 46: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

PHPUnit: Data Providers

• A data provider is a method that returns an array of parameters to pass into a test method.

• A test method may test several inputs.

• Important to note that data provider methods are run before any setup so this cannot depend on any test doubles.

Page 47: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

protected function setUp() { $this->userStorage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface');

$entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface'); $entity_manager->expects($this->any()) ->method('getStorage') ->with('user') ->will($this->returnValue($this->userStorage));

$this->passwordService = $this->getMock('Drupal\Core\Password\PasswordInterface');

$this->testUser = $this->getMockBuilder('Drupal\user\Entity\User') ->disableOriginalConstructor() ->setMethods(['id', 'setPassword', 'save', 'getPassword']) ->getMock();

$this->userAuth = new UserAuth($entity_manager, $this->passwordService); }

Coming up: Definition of mock.

Page 48: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Mock - Type of test make a replica or imitation of something.orfaking the behavior of object

Coming up: Types of mocks

Page 49: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Mock Methods

getMock() and getMockBuilder()

Coming up: difference bw methods.

Page 50: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

when the defaults used by the getMock() method to generate the test double do not match your needs then you can use the getMockBuilder($type) method to customize the test double generation using a fluent interface. Here is a list of methods provided by the Mock Builder:

● setMethods(array $methods) can be called on the Mock Builder object to specify the methods that are to be replaced with a configurable test double. The behavior of the other methods is not changed. If you call setMethods(null), then no methods will be replaced.

● setConstructorArgs(array $args) can be called to provide a parameter array that is passed to the original class' constructor (which is not replaced with a dummy implementation by default).

● setMockClassName($name) can be used to specify a class name for the generated test double class.

● disableOriginalConstructor() can be used to disable the call to the original class' constructor.

● disableOriginalClone() can be used to disable the call to the original class' clone constructor.

● disableAutoload() can be used to disable __autoload() during the generation of the test double class.

Page 51: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

STUBThe practice of replacing an object with a test double that (optionally) returns configured return values is

referred to as stubbing.

Page 52: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

THE FOUR PATHWAYS OF GETMOCKBUILDER()

Page 53: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Do not call setMethods()This is the simplest way:

$this->testUser = $this->getMockBuilder('Drupal\user\Entity\User') ->getMock();This produces a mock object where the methods

● Are all stubs,● All return null by default,● Are easily overridable

Page 54: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Passing an empty arrayYou can pass an empty array to setMethods():

$this->testUser = $this->getMockBuilder('Drupal\user\Entity\User') ->getMock(); ->setMethods(array()) ->getMock();This produces a mock object that is exactly the same as if you have not called setMethods() at all. The methods● Are all stubs,● All return null by default,● Are easily overridable

Page 55: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Passing nullYou can also pass null:

$this->testUser = $this->getMockBuilder('Drupal\user\Entity\User') ->setMethods(null) ->getMock();This produces a mock object where the methods

● Are all mocks,● Run the actual code contained within the method

when called,● Do not allow you to override the return value

Page 56: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Passing an array containing method names$this->testUser = $this->getMockBuilder('Drupal\user\Entity\User') ->setMethods(array(‘id', 'setPassword', 'save', 'getPassword’)) ->getMock();This produces a mock object whose methods are a mix of the above three scenarios.

Page 57: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

The methods you have identified

● Are all stubs,● All return null by default,● Are easily overridable

Methods you did not identify

● Are all mocks,● Run the actual code contained within the method

when called,● Do not allow you to override the return value

Page 58: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

This means that in the $this->testUser mock object the ‘id()', 'setPassword()', 'save()' and 'getPassword()’ methods would return null or you can override their return values, but any method within that class other than those four will run their original code.

Page 59: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

If you compare it to debugging:

Stub is like making sure a method returns the correct value

Mock is like actually stepping into the method and making sure everything inside is correct before returning the correct value.

Page 60: DRUPAL CON NASHVILLE CON... · Drupal 8: Let’s dive into PHPUnit testing. Sugandh Khanna Srijan, INDIA Drupal CON NASHVILLE March 2018

Any Questions?