SlideShare a Scribd company logo
PhpUnit модульне тестування
Короткий опис модульного тестування з використанням
фреймворка PhpUnit
1. Типи тестів:
• Модульні тести (юніт тести)
Тести найменших одиниць функціональності (модулів). Перевірка, чи функція, яка тестується
виконує саме те, для чого вона реалізована.
• Інтеграційні тести
Поєднує різні одиниці коду (різні модулі). Перевірка чи правильно працює їхня комбінація.
• Системні тести
• Прийомочні тести
2. Структура папок
tests/
unit/
Http/
Controllers/
TenderControllerTest.php
integration/
TenderStatusesTest.php
helpers/
UserHelper.php
3. Приклад модульного теста
use path/Default.php // підключення файла для тесту
class defaultTests extends PHPUnit_Framework_TestCase
{
private $default;
protected function setUp() // метод, який викликається перед кожним тестом (незалежно від кількості)
{
$this->default = new Default();
}
protected function tearDown() // метод, який викликається після кожного теста (незалежно від кількості)
{
$this-> default = NULL;
}
public function testAdd() // метод тест для метода add() класса Default()
{
$result = $this->default->add(1, 2);
$this->assertEquals(3, $result); //перевірка чи метод повернув правильний результат
}
}
4. Запуск і результат тесту:
phpunit tests/DefaultTest.php
PHPUnit 3.7.32 by Sebastian Bergmann.
.
Time: 31ms, Memory: 2.25Mb
OK (1 test, 1 assertion)
5. Використання різних наборів вхідних
данних
Без використання DataProvider
public function testAdd()
{
$result = $this->calculator->add(1, 2);
$this->assertEquals(3, $result);
}
public function testAddWithZero()
{
$result = $this->calculator->add(0, 0);
$this->assertEquals(0, $result);
}
public function testAddWithNegative()
{
$result = $this->calculator->add(-1, -1);
$this->assertEquals(-2, $result);
}
6. Використання різних наборів вхідних
данних
Метод, який являється DataProvider’ом, має повертати масив масивів.
Метод, який являється тестом буде викликатись декілька раз з кожним масивом, в якості аргументів будуть
передаватись вміст масиви.
Ключові моменти для використання dataProvider:
- метод dataProvider має бути публічним.
- метод dataProvider має повертати масив зібраних данних
- метод теcта має використовувати аннотоацію @dataProvider, щоб вказати, який метод має використовуватись в
якості dataProvider
7. Використання DataProvider
public function addDataProvider() {
return array(
array(1,2,3),
array(0,0,0),
array(-1,-1,-2),
);
}
/**
* @dataProvider addDataProvider
*/
public function testAdd($a, $b, $expected)
{
$result = $this->calculator->add($a, $b);
$this->assertEquals($expected, $result);
}
8. Asserts
assertEquals(‘foo’, ‘foo’)
assertTrue(!empty($result))
assertFalse(!empty($result))
assertArrayHasKey('foo', ['bar' => 'baz'])
assertClassHasAttribute('foo', stdClass::class)
assertContains(4, [1, 2, 3]);
assertCount(0, ['foo'])
assertDirectoryExists('/path/to/directory')
assertDirectoryIsReadable('/path/to/directory')
assertFileExists('/path/to/file')
assertNull('foo')
assertRegExp('/foo/', 'bar')
https://phpunit.de/manual/current/en/appendixes.assertions.html
9. Mock
Іноді при тестуванні нам потрібно використовувати обєкти, поведінку яких ми не можемо контролювати. Для рішення цієї проблеми
можна використовувати mock-обєкти.
Наприклад нам потрібно працювати з базою данних. Наприклад є метод який робить важкий запрос в базу данних, який
виконується не часто і для нашого тесту не потрібно відтворювати сам запрос, але результат запросу потрібен.
Метод getMock створює mock-обєкт з таким самим набором методів, як і звичайний обєкт классу Database. Всі методи, за
замовченням, будуть повертати null, але ми можемо перегрузити потрібний нам метод.
9.1. Приклад використання Mock-обєкта
class Database {
/**
* повільний метод який буде викоритсаний
*/
public function reallyLongTime() {
$results = array(
array(1, 'test', 'foo value')
);
sleep(1000);
return $results;
}
}
Class DatabaseTest extends PHPUnit_Framework_TestCase {
private $db = null;
public function setUp() {
$this->db = new Database();
}
public function tearDown() {
unset($this->db);
}
public function testReallyLongReturn() {
$mock = $this->getMock('Database');
$result = array(
array(1, 'foo', 'bar test')
);
$mock->expects($this->any())
->method('reallyLongTime')
->will($this->returnValue($result));
$return = $mock->reallyLongTime();
$this→assertTrue(count($result) == 3);
}
}

При кожному виклику метода reallyLongTime обєкта $mock буде повертатись значення змінної $result, замість реального виконання методу.
9.2 MockBuilder
При роботі з MockBuilder першим методом в ланцюгу викликів має бути getMockBuilder(), а останнім — getMock(). Наприклад, в наступному прикладі ми
створюємо mock-обєкт, которий не використовує конструктор, а також вимикає autoload:
function testReallyLongRunBuilder() {
$stub = $this->getMockBuilder('Database')
->setMethods(array(
'reallyLongTime'
))
->disableAutoload()
->disableOriginalConstructor()
->getMock();
$result = array(array(1, 'foo', 'bar test'));
$stub->expects($this->any())
->method('reallyLongTime')
->will($this->returnValue($result));
$this->assertGreaterThan(0, count($return));
}
public function getMock(
$originalClassName, // назва оригінального класса, для якого буде створений Mock обєкт
$methods = array(), // Массив методів для заміни, якщо вказати null методи будуть без підміни
array $arguments = array(), // аргументи, які передаються в конструктор
$mockClassName = '', // можна вказати імя Mock класа
$callOriginalConstructor = true, // відключити __construct()
$callOriginalClone = true, // відключити __clone()
$callAutoload = true // відключити __autoload()
);
$mock = $this->getMockBuilder('MyClass')
->setMethods(null)
->setConstructorArgs(array())
->setMockClassName('')
->disableOriginalConstructor()
->disableOriginalClone()
->disableAutoload()
->getMock();
Послідовність методів починається з метода getMockBuilder() и закінчується методом getMock() —
ці методи обовязкові.
9.3. Очікування виклику методів
PHPUnit дозволяє нам контролювати кількість і порядок викликів підмінених методів. Для цього використовується конструкція
expects() з вказуванням потрібного метода за допомогою - method().

public function test_process() {

$mock = $this->getMock('MyClass', array('getTemperature', 'getWord', 'showWord'));

$mock->expects($this->once())->method('getTemperature');

$mock->expects($this->once())->method('showWord');

$mock->expects($this->once())->method('getWord');

$mock->process();

}


Результат виконання этого теста будет успешным, если при вызове метода process() произойдет однократный вызов трех
перечисленных методов: getTemperature(), getWord(), showWord(). Обратите внимание, что в тесте проверка вызова getWord()
стоит после проверки вызова showWord(), хотя в тестируемом методе наоборот. Все верно, ошибки здесь нет. Для контроля
порядка вызова методов в PHPUnit используется другая конструкция — at(). Поправим немного код нашего теста так чтобы
PHPUnit проверил заодно очередность вызова методов:

public function test_process() {

$mock = $this->getMock('MyClass', array('getTemperature', 'getWord', 'showWord'));

$mock->expects($this->at(0))->method('getTemperature');

$mock->expects($this->at(2))->method('showWord');

$mock->expects($this->at(1))->method('getWord');

$mock->process();

}


Помимо упомянутых once() и at() для тестирования ожиданий вызовов в PHPUnit есть также следующие конструкции: any(),
never(), atLeastOnce() и exactly($count). Их названия говорят сами за себя.

More Related Content

PPTX
PDF
Тестування з допомогою PHPUnit
PPT
07 Containers
PDF
Тестування при розробці програмного забезпечення. Unit Tests.
PPT
01 Incapsulation
PPTX
IT Talks The c++'s simplest smart pointers in depth
PPT
07 Localisation
Тестування з допомогою PHPUnit
07 Containers
Тестування при розробці програмного забезпечення. Unit Tests.
01 Incapsulation
IT Talks The c++'s simplest smart pointers in depth
07 Localisation

What's hot (20)

PPT
JavaScript. Lectures. part 1. basis
PPTX
tsql
PPT
08 Functions
PPTX
SQL: Indexes, Select operator
PPTX
SQL Grouping, Joins
PDF
Coding for Future in Lutsk. JavaScript. Part 6
PPT
PPTX
01 c# basics
PDF
Coding for Future in Lutsk. JavaScript. Part 3
PPTX
Design patterns part 2
PDF
Lect 6 prolog
PDF
"Is there life in react without redux" by Babich Sergiy. OdessaJS'2021
PPTX
передача параметрів в функції
PPT
09 Object And Class Hierarchy
PPT
лекция 14 phylo
PPT
08 Templates
PPTX
PPTX
Design patterns part 1
JavaScript. Lectures. part 1. basis
tsql
08 Functions
SQL: Indexes, Select operator
SQL Grouping, Joins
Coding for Future in Lutsk. JavaScript. Part 6
01 c# basics
Coding for Future in Lutsk. JavaScript. Part 3
Design patterns part 2
Lect 6 prolog
"Is there life in react without redux" by Babich Sergiy. OdessaJS'2021
передача параметрів в функції
09 Object And Class Hierarchy
лекция 14 phylo
08 Templates
Design patterns part 1
Ad

Viewers also liked (18)

PDF
Towards a Better Understanding of the Impact of Experimental Components on De...
PDF
Pastoral. Trobada intercol.legial. Fem Camí 2017
PDF
Ingeniería mecánica estática willian f. riley
PDF
Ssit informacoesgerenciais 5
PPTX
Calcium and Hypertension
PPT
Motores universais
DOCX
Hakikat supervisi kependidikan 2
PDF
Silo vertical cgr cv
PPTX
Як функціонує державна влада в Україні
DOCX
Executive summary agrivol it rev a
PDF
Artificial Intelligence in Medical Imaging: An Analysis of Funding for Start-ups
PPT
съчинение по наблюдение
DOCX
Derecho Procesal Penal II
PPT
Presentación Prezi
PDF
Csi pavia notizie_n_10_del_14.03.17
PPSX
A importância da oratória em todas as áreas da vida
PPTX
Autobiografía
DOCX
Relatoria de la biografia
Towards a Better Understanding of the Impact of Experimental Components on De...
Pastoral. Trobada intercol.legial. Fem Camí 2017
Ingeniería mecánica estática willian f. riley
Ssit informacoesgerenciais 5
Calcium and Hypertension
Motores universais
Hakikat supervisi kependidikan 2
Silo vertical cgr cv
Як функціонує державна влада в Україні
Executive summary agrivol it rev a
Artificial Intelligence in Medical Imaging: An Analysis of Funding for Start-ups
съчинение по наблюдение
Derecho Procesal Penal II
Presentación Prezi
Csi pavia notizie_n_10_del_14.03.17
A importância da oratória em todas as áreas da vida
Autobiografía
Relatoria de la biografia
Ad

Similar to Phpunit модульне тестування (19)

PDF
Php unit. Y. Muzychushun
PDF
Tdd, ти де?
PDF
WordPress meetup Kyiv - Starting theme
PPT
05 Operations And Utilities
PDF
12 - gradle. evoliutsiia system avtomatychnoi zbirky - sviatoslav babych - it...
PPTX
cpp-2013 #16 Automated testing
PPTX
Clean code (UA)
PDF
07 - vysnovky z tdd, pohliad pochatkivtsia - vitalii zinchenko it event 2013...
PPTX
cpp-2013 #20 Best practices
PPT
02 Copying Objects
PPTX
Automated testing
PPT
Oop - TTm
PPTX
Слайди презентації для лекції Функції РНР для роботи з базами даних
PPTX
PPT
11 Iterated Containers
PPT
Prometheus. Масовий онлайн курс "Основи програмування". Лекція 5
PDF
Coding for Future in Lutsk. JavaScript. Part 11
PPTX
Advanced C#. Part 2
Php unit. Y. Muzychushun
Tdd, ти де?
WordPress meetup Kyiv - Starting theme
05 Operations And Utilities
12 - gradle. evoliutsiia system avtomatychnoi zbirky - sviatoslav babych - it...
cpp-2013 #16 Automated testing
Clean code (UA)
07 - vysnovky z tdd, pohliad pochatkivtsia - vitalii zinchenko it event 2013...
cpp-2013 #20 Best practices
02 Copying Objects
Automated testing
Oop - TTm
Слайди презентації для лекції Функції РНР для роботи з базами даних
11 Iterated Containers
Prometheus. Масовий онлайн курс "Основи програмування". Лекція 5
Coding for Future in Lutsk. JavaScript. Part 11
Advanced C#. Part 2

Phpunit модульне тестування

  • 1. PhpUnit модульне тестування Короткий опис модульного тестування з використанням фреймворка PhpUnit
  • 2. 1. Типи тестів: • Модульні тести (юніт тести) Тести найменших одиниць функціональності (модулів). Перевірка, чи функція, яка тестується виконує саме те, для чого вона реалізована. • Інтеграційні тести Поєднує різні одиниці коду (різні модулі). Перевірка чи правильно працює їхня комбінація. • Системні тести • Прийомочні тести
  • 4. 3. Приклад модульного теста use path/Default.php // підключення файла для тесту class defaultTests extends PHPUnit_Framework_TestCase { private $default; protected function setUp() // метод, який викликається перед кожним тестом (незалежно від кількості) { $this->default = new Default(); } protected function tearDown() // метод, який викликається після кожного теста (незалежно від кількості) { $this-> default = NULL; } public function testAdd() // метод тест для метода add() класса Default() { $result = $this->default->add(1, 2); $this->assertEquals(3, $result); //перевірка чи метод повернув правильний результат } }
  • 5. 4. Запуск і результат тесту: phpunit tests/DefaultTest.php PHPUnit 3.7.32 by Sebastian Bergmann. . Time: 31ms, Memory: 2.25Mb OK (1 test, 1 assertion)
  • 6. 5. Використання різних наборів вхідних данних Без використання DataProvider public function testAdd() { $result = $this->calculator->add(1, 2); $this->assertEquals(3, $result); } public function testAddWithZero() { $result = $this->calculator->add(0, 0); $this->assertEquals(0, $result); } public function testAddWithNegative() { $result = $this->calculator->add(-1, -1); $this->assertEquals(-2, $result); }
  • 7. 6. Використання різних наборів вхідних данних Метод, який являється DataProvider’ом, має повертати масив масивів. Метод, який являється тестом буде викликатись декілька раз з кожним масивом, в якості аргументів будуть передаватись вміст масиви. Ключові моменти для використання dataProvider: - метод dataProvider має бути публічним. - метод dataProvider має повертати масив зібраних данних - метод теcта має використовувати аннотоацію @dataProvider, щоб вказати, який метод має використовуватись в якості dataProvider
  • 8. 7. Використання DataProvider public function addDataProvider() { return array( array(1,2,3), array(0,0,0), array(-1,-1,-2), ); } /** * @dataProvider addDataProvider */ public function testAdd($a, $b, $expected) { $result = $this->calculator->add($a, $b); $this->assertEquals($expected, $result); }
  • 9. 8. Asserts assertEquals(‘foo’, ‘foo’) assertTrue(!empty($result)) assertFalse(!empty($result)) assertArrayHasKey('foo', ['bar' => 'baz']) assertClassHasAttribute('foo', stdClass::class) assertContains(4, [1, 2, 3]); assertCount(0, ['foo']) assertDirectoryExists('/path/to/directory') assertDirectoryIsReadable('/path/to/directory') assertFileExists('/path/to/file') assertNull('foo') assertRegExp('/foo/', 'bar') https://phpunit.de/manual/current/en/appendixes.assertions.html
  • 10. 9. Mock Іноді при тестуванні нам потрібно використовувати обєкти, поведінку яких ми не можемо контролювати. Для рішення цієї проблеми можна використовувати mock-обєкти. Наприклад нам потрібно працювати з базою данних. Наприклад є метод який робить важкий запрос в базу данних, який виконується не часто і для нашого тесту не потрібно відтворювати сам запрос, але результат запросу потрібен. Метод getMock створює mock-обєкт з таким самим набором методів, як і звичайний обєкт классу Database. Всі методи, за замовченням, будуть повертати null, але ми можемо перегрузити потрібний нам метод.
  • 11. 9.1. Приклад використання Mock-обєкта class Database { /** * повільний метод який буде викоритсаний */ public function reallyLongTime() { $results = array( array(1, 'test', 'foo value') ); sleep(1000); return $results; } } Class DatabaseTest extends PHPUnit_Framework_TestCase { private $db = null; public function setUp() { $this->db = new Database(); } public function tearDown() { unset($this->db); } public function testReallyLongReturn() { $mock = $this->getMock('Database'); $result = array( array(1, 'foo', 'bar test') ); $mock->expects($this->any()) ->method('reallyLongTime') ->will($this->returnValue($result)); $return = $mock->reallyLongTime(); $this→assertTrue(count($result) == 3); } }  При кожному виклику метода reallyLongTime обєкта $mock буде повертатись значення змінної $result, замість реального виконання методу.
  • 12. 9.2 MockBuilder При роботі з MockBuilder першим методом в ланцюгу викликів має бути getMockBuilder(), а останнім — getMock(). Наприклад, в наступному прикладі ми створюємо mock-обєкт, которий не використовує конструктор, а також вимикає autoload: function testReallyLongRunBuilder() { $stub = $this->getMockBuilder('Database') ->setMethods(array( 'reallyLongTime' )) ->disableAutoload() ->disableOriginalConstructor() ->getMock(); $result = array(array(1, 'foo', 'bar test')); $stub->expects($this->any()) ->method('reallyLongTime') ->will($this->returnValue($result)); $this->assertGreaterThan(0, count($return)); }
  • 13. public function getMock( $originalClassName, // назва оригінального класса, для якого буде створений Mock обєкт $methods = array(), // Массив методів для заміни, якщо вказати null методи будуть без підміни array $arguments = array(), // аргументи, які передаються в конструктор $mockClassName = '', // можна вказати імя Mock класа $callOriginalConstructor = true, // відключити __construct() $callOriginalClone = true, // відключити __clone() $callAutoload = true // відключити __autoload() ); $mock = $this->getMockBuilder('MyClass') ->setMethods(null) ->setConstructorArgs(array()) ->setMockClassName('') ->disableOriginalConstructor() ->disableOriginalClone() ->disableAutoload() ->getMock(); Послідовність методів починається з метода getMockBuilder() и закінчується методом getMock() — ці методи обовязкові.
  • 14. 9.3. Очікування виклику методів PHPUnit дозволяє нам контролювати кількість і порядок викликів підмінених методів. Для цього використовується конструкція expects() з вказуванням потрібного метода за допомогою - method().  public function test_process() {  $mock = $this->getMock('MyClass', array('getTemperature', 'getWord', 'showWord'));  $mock->expects($this->once())->method('getTemperature');  $mock->expects($this->once())->method('showWord');  $mock->expects($this->once())->method('getWord');  $mock->process();  }   Результат виконання этого теста будет успешным, если при вызове метода process() произойдет однократный вызов трех перечисленных методов: getTemperature(), getWord(), showWord(). Обратите внимание, что в тесте проверка вызова getWord() стоит после проверки вызова showWord(), хотя в тестируемом методе наоборот. Все верно, ошибки здесь нет. Для контроля порядка вызова методов в PHPUnit используется другая конструкция — at(). Поправим немного код нашего теста так чтобы PHPUnit проверил заодно очередность вызова методов:  public function test_process() {  $mock = $this->getMock('MyClass', array('getTemperature', 'getWord', 'showWord'));  $mock->expects($this->at(0))->method('getTemperature');  $mock->expects($this->at(2))->method('showWord');  $mock->expects($this->at(1))->method('getWord');  $mock->process();  }   Помимо упомянутых once() и at() для тестирования ожиданий вызовов в PHPUnit есть также следующие конструкции: any(), never(), atLeastOnce() и exactly($count). Их названия говорят сами за себя.