phpunit

# Getting started with phpunit

## Remarks#

This section provides an overview of what phpunit is, and why a developer might want to use it.

It should also mention any large subjects within phpunit, and link out to the related topics. Since the Documentation for phpunit is new, you may need to create initial versions of those related topics.

## Versions#

VersionSupport endsSupported in those PHP versionsRelease date
5.42016-08-05PHP 5.6, PHP 7.2016-06-03
4.82017-02-03PHP 5.3, PHP 5.4, PHP 5.5, and PHP 5.6.2015-08-07

## Create first PHPUnit test for our class

Imagine that we have a class `Math.php` with logic of calculating of fiobanacci and factorial numbers. Something like this:

``````<?php
class Math {
public function fibonacci(\$n) {
if (is_int(\$n) && \$n > 0) {
\$elements = array();
\$elements[1] = 1;
\$elements[2] = 1;
for (\$i = 3; \$i <= \$n; \$i++) {
}
return \$elements[\$n];
} else {
throw new
InvalidArgumentException('You should pass integer greater than 0');
}
}

public function factorial(\$n) {
if (is_int(\$n) && \$n >= 0) {
\$factorial = 1;
for (\$i = 2; \$i <= \$n; \$i++) {
\$factorial *= \$i;
}
return \$factorial;
} else {
throw new
InvalidArgumentException('You should pass non-negative integer');
}
}
}``````

## The simplest test

We want to test logic of methods `fibonacci` and `factorial`. Let’s create file `MathTest.php` into the same directory with `Math.php`. In our code we can use different assertions. The simplest code will be something like this (we use only `assertEquals` and `assertTrue`):

``````<?php
require 'Math.php';

use PHPUNIT_Framework_TestCase as TestCase;
// sometimes it can be
// use PHPUnit\Framework\TestCase as TestCase;

class MathTest extends TestCase{
public function testFibonacci() {
\$math = new Math();
\$this->assertEquals(34, \$math->fibonacci(9));
}

public function testFactorial() {
\$math = new Math();
\$this->assertEquals(120, \$math->factorial(5));
}

public function testFactorialGreaterThanFibonacci() {
\$math = new Math();
\$this->assertTrue(\$math->factorial(6) > \$math->fibonacci(6));
}
}``````

We can run this test from console with command `phpunit MathTest` and output will be:

``````    PHPUnit 5.3.2 by Sebastian Bergmann and contributors.

...                                                                 3 / 3 (100%)

Time: 88 ms, Memory: 10.50Mb

OK (3 tests, 3 assertions)``````

## Using dataProviders

A test method can accept arbitrary arguments. These arguments are to be provided by a data provider method. The data provider method to be used is specified using the `@dataProvider` annotation. :

``````<?php
require 'Math.php';

use PHPUNIT_Framework_TestCase as TestCase;
// sometimes it can be
// use PHPUnit\Framework\TestCase as TestCase;

class MathTest extends TestCase {
/**
* test with data from dataProvider
* @dataProvider providerFibonacci
*/
public function testFibonacciWithDataProvider(\$n, \$result) {
\$math = new Math();
\$this->assertEquals(\$result, \$math->fibonacci(\$n));
}

public function providerFibonacci() {
return array(
array(1, 1),
array(2, 1),
array(3, 2),
array(4, 3),
array(5, 5),
array(6, 8),
);
}
}``````

We can run this test from console with command `phpunit MathTest` and output will be:

``````    PHPUnit 5.3.2 by Sebastian Bergmann and contributors.

......                                                              6 / 6 (100%)

Time: 97 ms, Memory: 10.50Mb

OK (6 tests, 6 assertions)

<?php
require 'Math.php';
use PHPUNIT_Framework_TestCase as TestCase;
// sometimes it can be
// use PHPUnit\Framework\TestCase as TestCase;``````

## Test exceptions

We can test whether an exception is thrown by the code under test using method `expectException()`. Also in this example we add one failed test to show console output for failed tests.

``````<?php
require 'Math.php';
use PHPUNIT_Framework_TestCase as TestCase;
// sometimes it can be
// use PHPUnit\Framework\TestCase as TestCase;

class MathTest extends TestCase {
public function testExceptionsForNegativeNumbers() {
\$this->expectException(InvalidArgumentException::class);
\$math = new Math();
\$math->fibonacci(-1);
}

public function testFailedForZero() {
\$this->expectException(InvalidArgumentException::class);
\$math = new Math();
\$math->factorial(0);
}
}``````

We can run this test from console with command `phpunit MathTest` and output will be:

``````        PHPUnit 5.3.2 by Sebastian Bergmann and contributors.

.F                                                                  2 / 2 (100%)

Time: 114 ms, Memory: 10.50Mb

There was 1 failure:

1) MathTest::testFailedForZero
Failed asserting that exception of type "InvalidArgumentException" is thrown.

FAILURES!
Tests: 2, Assertions: 2, Failures: 1.``````

## SetUp and TearDown

Also `PHPUnit` supports sharing the setup code. Before a test method is run, a template method called setUp() is invoked. `setUp()` is where you create the objects against which you will test. Once the test method has finished running, whether it succeeded or failed, another template method called `tearDown()` is invoked. `tearDown()` is where you clean up the objects against which you tested.

``````<?php
require 'Math.php';

use PHPUNIT_Framework_TestCase as TestCase;
// sometimes it can be
// use PHPUnit\Framework\TestCase as TestCase;

class MathTest extends TestCase {
public \$fixtures;
protected function setUp() {
\$this->fixtures = [];
}

protected function tearDown() {
\$this->fixtures = NULL;
}

public function testEmpty() {
\$this->assertTrue(\$this->fixtures == []);
}
}``````

There are much more great opportunities of `PHPUnit` which you can use in your test. For more info see in official manual

## Minimal example test

Given a simple PHP class:

``````class Car
{
private \$speed = 0;

public getSpeed() {
return \$this->speed;
}

public function accelerate(\$howMuch) {
\$this->speed += \$howMuch;
}
}``````

You can write a PHPUnit test which tests the behavior of the class under test by calling the public methods and check whether they function as expected:

``````class CarTest extends PHPUnit_Framework_TestCase
{
public function testThatInitalSpeedIsZero() {
\$car = new Car();
\$this->assertSame(0, \$car->getSpeed());
}

public function testThatItAccelerates() {
\$car = new Car();
\$car->accelerate(20);
\$this->assertSame(20, \$car->getSpeed());
}

public function testThatSpeedSumsUp() {
\$car = new Car();
\$car->accelerate(30);
\$car->accelerate(50);
\$this->assertSame(80, \$car->getSpeed());
}
}``````

Important parts:

1. Test class needs to derive from PHPUnit_Framework_TestCase.
3. Use `\$this->assert...` functions to check expected values.

## Mocking classes

The practice of replacing an object with a test double that verifies expectations, for instance asserting that a method has been called, is referred to as mocking.

Lets assume we have SomeService to test.

``````class SomeService
{
private \$repository;
public function __construct(Repository \$repository)
{
\$this->repository = \$repository;
}

public function methodToTest()
{
\$this->repository->save('somedata');
}
}   ``````

And we want to test if `methodToTest` really calls `save` method of repository. But we don’t want to actually instantiate repository (or maybe `Repository` is just an interface).

In this case we can mock `Repository`.

``````use PHPUnit\Framework\TestCase as TestCase;

class SomeServiceTest extends TestCase
{
/**
* @test
*/
public function testItShouldCallRepositorySavemethod()
{
// create an actual mock
\$repositoryMock = \$this->createMock(Repository::class);

\$repositoryMock->expects(\$this->once()) // test if method is called only once
->method('save')                   // and method name is 'save'
->with('somedata');                // and it is called with 'somedata' as a parameter

\$service = new SomeService(\$repositoryMock);
\$service->someMethod();
}
}

## Example of PHPUNIT with APItest using Stub And Mock
Class for which you will create unit test case.
<code>
class Authorization {

/* Observer so that mock object can work. */
public function attach(Curl \$observer)
{
\$this->observers = \$observer;
}

/* Method for which we will create test */
public  function postAuthorization(\$url, \$method) {

return \$this->observers->callAPI(\$url, \$method);
}
}
</code>

Now we did not want any external interaction of our test code thus we need to create a mock object for callAPI function as this function is actually calling external url via curl.
<code>
class AuthorizationTest extends PHPUnit_Framework_TestCase {

protected \$Authorization;

/**
* This method call every time before any method call.
*/
protected function setUp() {
\$this->Authorization = new Authorization();
}

/**
* Test Login with invalid user credential
*/

/*creating mock object of Curl class which is having callAPI function*/
\$observer = \$this->getMockBuilder('Curl')
->setMethods(array('callAPI'))
->getMock();

/* setting the result to call API. Thus by default whenver call api is called via this function it will return invalid user message*/
\$observer->method('callAPI')
->will(\$this->returnValue('"Invalid user credentials"'));

/* attach the observer/mock object so that our return value is used */
\$this->Authorization->attach(\$observer);

/* finally making an assertion*/
\$this->assertEquals('"Invalid user credentials"',           \$this->Authorization->postAuthorization('/authorizations', 'POST'));
}
}
</code>

Below is the code for curl class(just a sample)
<code>
class Curl{
function callAPI(\$url, \$method){

//sending curl req
}
}
</code>
``````

This modified text is an extract of the original Stack Overflow Documentation created by the contributors and released under CC BY-SA 3.0 This website is not affiliated with Stack Overflow