SlideShare a Scribd company logo
1 of 20
PHP Unit
ОСНОВИ МОДУЛЬНОГО І ІНТЕГРАЦІЙНОГО ТЕСТУВАННЯ
Типи тестування
 Модульне(Unit testing) — тестування одного окремого модуля (метода).
 Інтеграційне(Integration Testing) — тестування групи взаємодіючих
модулів.
 Системне (System Testing) — тестування системы вцілому.
Опис модульного тестування
Мета:
 Ізолювати окремі частини програми і показати, що ці окремі модулі
працездатні.
 Можливість безболісно проводити рефакторінг
 «Живий документ» тестованого модуля (можливість швидко розібратись з
логікою модуля)
 Перевірка якості коду модуля (всі можливі/неможливі вхідні/вихідні данні)
Типи:
 Тести стану (state based) – перевіряють, що викликаний метод обєкта обробився
коректно, превіряючи стан тестованого обєкта після виклику метода.
 Тести взаємодії (interaction tests) – тест в якому тестований обєкт виконує маніпуляції з
другими обєктами. Приміняються тоді, коли потрібно переконатись, що тестований
обєкт коректно взаємодіє з іншими обєктами.
Зовнішня залежність в тестах
Модульні тести:
Використання mock/stub обєктів, замість прямого звязку з БД, або іншими
зовнішніми системами.
Інтеграційні тести:
Використання прямих підключень і запитів до БД з використанням
транзакцій, або до інших зовнішніх систем.
Приклад модульного тесту
Tender {
public function checkDate($date){
if($date > date(‘d-m-Y’, time())){
return ‘success’;
} else {
return ‘error’;
}
}
}
TenderTest {
public function testCheckDate() {
$date = date(‘d-m-Y’, time()+3600); //null, another date format, date with spaces
$result = (new Tender())->checkDate($date);
$this->assertTrue($result == ‘success’);
}
}
Data provider
Dataprovider використовується для різних наборів вхідних данних.
Метод, який являється DataProvider’ом, має повертати масив масивів, або обєкт.
Метод, який являється тестом буде викликатись декілька раз з кожним масивом,
в якості аргументів будуть передаватись вміст масиву.
Ключові моменти для використання dataProvider:
- dataProvider має бути статичним публічним методом.
- dataProvider має повертати масив зібраних данних
- тест має використовувати аннотацію @dataProvider, щоб вказати, який метод
має використовуватись в якості dataProvider
Приклад використання data provider
Public static function dateProvider(){
return [
[date(‘d-m-Y’, time()), ‘error’],
[date(‘d-m-Y’, time()+3600), ‘success’],
[null, ‘error’]
];
}
/**
* @dataProvider dateProvider
*/
public function testCheckDate($date, $result) {
$res = (new Tender())->checkDate($date);
$this->assertTrue($res == $result);
}
Asserts (перевірки)
 assertTrue($bool[, $message])
 assertArrayHasKey($key, $array[,$message])
 assertClassHasAttribute($attr. $className)
 assertContains($needle, $array|$string|$integer)
 assertDirectoryExist($path)
 assertDirectoryReadable($path)
 assertEmpty($val)
 assertFileExist($pathToFile)
 assertGreaterThan($val1, $val2)
 assertInstanceOf($class, $object)
 assertRegExp($pattern, $string)
Приклад використання asserts
public function testCreateDate() {
$date = date(‘d-m-Y’,time()+3600);
$res = (new Tender())→createDate($date);
$message1 = ‘createDate() не повертає обєкт, классу
Date()’;
$message2 = ‘в классі Date() немає аттрибуту $formDate’;
$message3 = ‘метод createDate() не відформатував
$date’;
$this→assertInstanceOf(Date(), $res, $message1);
$this→assertClassHasAttribute(‘formatDate’, ‘Date’,
$message2);
$this→assertTrue($date != $res→formatDate, $message3)
}
public function createDate($date){
if($date > date(‘d-m-Y’, time())){
return new Date($date);
} else {
return null;
}
}
Class Date{
public $formatDate;
public function __constructor($date){
$this→formatDate = date(‘Y-m-d’, strtotime($date));
}
}
Залежності тестів
 Producer – тестовий метод, котрий повертає значення,
від яких залежать інші методи модуля.
 Consumer – тестовий метод, котрий залежить від
одного або більше методів (producer) і значень, які
вони повертають.
 Для позначенняя залежного метода, використовується
анотація @depends

 public function testEmpty(){
 $stack = array();
 $this->assertTrue(empty($stack));
 return $stack;
 }
 /**
 * @depends testEmpty
 */
 public function testPush(array $stack) {
 array_push($stack, 'foo');
 $this->assertEquals('foo', $stack[count($stack)-1]);
 $this->assertFalse(empty($stack));
 return $stack;
 }
 /**
 * @depends testPush
 */
 public function testPop(array $stack)
 {
 $this->assertEquals('foo', array_pop($stack));
 $this->assertTrue(empty($stack));
 }
 }

Тестування виключень (exception)
 Метод який повертає exeption
 public function returnException() {
 $this->setException('InvalidArgException');
 }
 Перевірка exeption в тесті
 /**
 * @expectedException InvalidArgException<br>
 */
 public function testException() {
 (new SomeClass())->returnException();
 $this->assertTrue(true);
 }
Mock, Stub класи заглушки (дублери)
 Коли потрібно використовувати класи дублери:
 Необхідність можливості запуску тестів незалежно де (на машині любого розробника в любій ОС)
 Коли результат запиту до БД/api нам стовідсотково відомий і нам не потрібно його перевіряти.
 Низька швидкість виконання тестів з реальними обєктами (наприклад робота з БД, файламию поштовим сервером,
сторонніми api)
 Типи класів дублерів:
 Dummy – обєкти котрі передаються в методиб але насправді не використовуються. В основному це параметри методів
(якщо вони не впливають в тесті на те, що ми хочемо перевірити). Іноді це просто null.
 Fake – це обєкти, котрі мають внутрішню реалізацію, але зазвичай вона урізана і їх не можна використовувати в
готовому коді.
 Stubs – обеспечують чітко зашиту відповідб на виклик під час тестування. Приміняються для заміни тих обєктів, які
забезпечують тест вхідними данними. Також вони можуть зберігати в соб інформацію про виклики (наприклад
параметри і кількість викликів).
 Mocks – обєкти, котрі налаштовуються (наприклад специфічно під кожен тест) і дозволяють задавати очікування в
вигляді свого роду специфікації викликів, які ми плануємо отримати.
 Mock – використовується для тестів на поведінку обєкта.
 Всі інші дублі використовуються для тестуванння стану обєкта після виклику метода.
Методи по роботі з класами дублями (Mock)
 public function getMock(
 $originalClassName, // назва оригінального класу, для котрого буде
створений Mock объект
 $methods = array(), // масив методів які будуть замінені
 array $arguments = array(), // аргументи, як передаються в конструктор
 $mockClassName = '', // можна вказать імя Mock класа
 $callOriginalConstructor = true, // відключення виклику конструктора
 $callOriginalClone = true, // відключення виклику __clone()
 $callAutoload = true // відключення виклику __autoload()
 );
 Якщо другим аргументом в getMock() передати null, тоді жоден метод не
буде замінений.
 Додаткові способи виклику Mock обєкта:
 $mock = $this->getMockBuilder('MyClass')
 ->setMethods(null)
 ->setConstructorArgs(array())
 ->setMockClassName('')
 ->disableOriginalConstructor()
 ->disableOriginalClone()
 ->disableAutoload()
 →getMock();
 getMockClass() — створює Mock класс і повертає його назву у вигляді
строки;
 getMockForAbstractClass() — повертає Mock обєкт абстрактного класа, в
котрому замінені всі абстрактні методи.

Очікування виклику метода
 PHPUnit дозволяєє нам контролювати кількість і порядок викликів підмінених методів, для цього використовується
метод expects()
 public function test_process() {
 $mock = $this->getMock('MyClass', array('getTemperature', 'getWord'));
 $mock->expects($this->once())->method('getTemperature');
 $mock->expects($this->once())->method('getWord');
 $mock->process();
 }
 Результат виконання цього тесту буде успішним, якщо при виклику метода process() відбудеться одноразовий виклик двох
вказаних методів: getTemperature(), getWord(). В такому випадку неважливий порядок виклику методів.
 Для контроля порядка виклику методів в PHPUnit використовується друга конструкція — at().
 public function test_process() {
 $mock = $this->getMock('MyClass', array('getTemperature', 'getWord'));
 $mock->expects($this->at(1))->method('getTemperature');
 $mock->expects($this->at(0))->method('showWord');
 $mock->process();
 }
 Окрім once() і at() для тестування очікування викликів в PHPUnit є також наступні конструкції: any(), never(), atLeastOnce() и
exactly($count).

Перевизначення (заміна) методів Mock обєктів
 Основною можливітю Mock обєктів, являється можливість заміни методів.
 Для перевизначення методів використовується метод will():
 $temperature = 20;
 $mock→expects($this→once())→method('getTemperature')→will($this→returnValue($temperature));

 Перевірка вказаних аргументів:
 Ще одна корисна для тестування можливість Mock обєктів являється перевірка аргументів, вказанных при виклику
подміненого метода, за допомогою конструкції with():

 public function test_with_and_will_usage() {
 $mock = $this->getMock('MyClass', array('getWord'));
 $mock->expects($this->once())
 ->method('getWord')
 ->with($this->greaterThan(25))
 ->will($this->returnValue('hot'));
 $this->assertEquals('hot', $mock->getWord(30));
 }
 В якості аргументів метод with() може приймати такі самі конструкції, що і перевірка assertThat():
 attribute(), anything(), arrayHasKey(), contains(), )fileExists(), greaterThan(), classHasAttribute(), classHasStaticAttribute(), hasAttribute(),
isFalse(), isInstanceOf(), isNull(), isTrue(), isType(), matchesRegularExpression(), stringContains()




Приклад використання mock обєкта.
 Class Tender{
 public function getCategories(){
 return (new Category)→getList(); //request to DB
 }
 public function checkCategory($category){
 return in_array($category, $this->getCategories());
 }
 }
 private $_categories = [1,2,3,4]
 public function testCheckCategories(){
 $mock = $this→getMock(‘Tender’, [‘getCategories’]);
 $this→assertInstanceOf(‘Tender’, $mock);
 $mock→expects($this→once())
 →method(‘getCategories’)→returnValue($this→
 ->returnValue($this->_categories);

 }
Тестове оточення (fixtures).
 Так як після завершення тесту всім змінним потрібно повернути попередні значення, створюється
тестове оточення (fixture).
 Для її створення використовуються методи:
 До того як почне виконувтись тест, викликається метод setUp();
 Як тільки тест завершиться, викликається метод tearDown();
 Також є інші методи, які викликаються в такій послідовності:
 setUpBeforeClass()
 setUp();
 assertPreConditions();
 testOne(); // тест
 assertPostConditions();
 tearDown();
Транзакції в тестуванні
 Транзакції зазвичай використовуються в інтеграційних тестах, в модульних використовуюься mock
обєкти для звязку з БД.
 public function setUp()
 {
 parent::setUp();
 DB::beginTransaction();
 }

 public function tearDown()
 {
 DB::rollBack();
 parent::tearDown();
 }
MVC
 Модель — містить бізнес-логіку додатку. Включає методи виборки,
обробки і надання конкретних данних, що зазвичай робить її дуже
великою, це нормально.

 Вид — використовується для відображення данних, отриманих з
контроллера і моделі.
 Вид містить HTML и невеликі вставки PHP-кода для форматування і
відображення данних.
 Не повинен напряму звертатись до БД.
 Не повинен працювати з данними, отриманими з запита користувача.
 Може напряму звертатись властивостей і методів контролера чи
моделі, для отримання готових данних.

 Контролер — звязок моделі і виду. Контроллер відповідає за обробку
запросів користувача. Контроллер не повинен містити SQL-запросів.
 Контроллер не повинен містити HTML.
 В гарно спроектованому MVC-додатку контролери зазвичай дуже
маленькі і містять лише декілка десятків строк коду.
 Модели, навпаки, дуже товсті і містять більшу частину кода, повязану з
Рефакторінг
 TenderController{
 public function store(Request $request){
 $data = $request→all();
 if(!empty($data[‘some’])){
 $data[‘result’] = true;
 }
 if(!empty($data[‘some2’])){
 $data[‘result2’] = false;
 }
 $tender = Tender::where(‘result’, $data[‘result’])
 ->orWhere(‘result2’, $data[‘result2’])
 ->orderBy('updated_at', 'asc')→get();

 if($tender→status == ‘lalala’){
 return false;
 } elseif($tender→status == ‘666’) {
 return false;
 } else {
 return true;
 }
 }
 }
 TenderController{
 public function store(Request $request, Tender $model){
 $data = $request→all();
 $data = $model->checkData($data);
 $tender = $model->getTender($data);
 return $tender->checkStatus()
 }
 }
 Model/Tender{
 public function checkData($data){
 if(!empty($data[‘some’])){
 $data[‘result’] = true;
 }
 if(!empty($data[‘some2’])){
 $data[‘result2’] = false;
 }
 return $data
 }
 public function getTender(){
 return self::where(‘result’, $data[‘result’])
 ->orWhere(‘result2’, $data[‘result2’])
 ->orderBy('updated_at', 'asc')→get()
 }
 public function checkStatus(){
 if($this→status == ‘lalala’){
 return false;
 } elseif($this→status == ‘666’) {
 return false;
 } else {
 return true;
 }
 }
 }

More Related Content

What's hot

System programing module 1
System programing module 1System programing module 1
System programing module 1Andrii Hladkyi
 
System programing module 2
System programing module 2System programing module 2
System programing module 2Andrii Hladkyi
 
Advanced c sharp part 3
Advanced c sharp part 3Advanced c sharp part 3
Advanced c sharp part 3eleksdev
 
System programing module 3
System programing module 3System programing module 3
System programing module 3Andrii Hladkyi
 
Php unit. Y. Muzychushun
Php unit. Y. MuzychushunPhp unit. Y. Muzychushun
Php unit. Y. MuzychushunHRdepartment
 
01 Incapsulation
01 Incapsulation01 Incapsulation
01 Incapsulationolegapster
 
01 c# basics
01 c# basics01 c# basics
01 c# basicseleksdev
 
Тестування при розробці програмного забезпечення. Unit Tests.
Тестування при розробці програмного забезпечення. Unit Tests.Тестування при розробці програмного забезпечення. Unit Tests.
Тестування при розробці програмного забезпечення. Unit Tests.Elantix
 
Prometheus. Масовий онлайн курс "Основи програмування". Лекція 7
Prometheus. Масовий онлайн курс "Основи програмування". Лекція 7Prometheus. Масовий онлайн курс "Основи програмування". Лекція 7
Prometheus. Масовий онлайн курс "Основи програмування". Лекція 7Nikita Pavliuchenko
 
Основнi моменти модульного тестування в Qt
Основнi моменти модульного тестування в QtОсновнi моменти модульного тестування в Qt
Основнi моменти модульного тестування в QtTrola.org
 
Advanced C#. Part 2
Advanced C#. Part 2Advanced C#. Part 2
Advanced C#. Part 2eleksdev
 
09 Object And Class Hierarchy
09 Object And Class Hierarchy09 Object And Class Hierarchy
09 Object And Class Hierarchyolegapster
 

What's hot (17)

Sql pl
Sql plSql pl
Sql pl
 
System programing module 1
System programing module 1System programing module 1
System programing module 1
 
System programing module 2
System programing module 2System programing module 2
System programing module 2
 
Advanced c sharp part 3
Advanced c sharp part 3Advanced c sharp part 3
Advanced c sharp part 3
 
Design patterns part 1
Design patterns part 1Design patterns part 1
Design patterns part 1
 
System programing module 3
System programing module 3System programing module 3
System programing module 3
 
Php unit. Y. Muzychushun
Php unit. Y. MuzychushunPhp unit. Y. Muzychushun
Php unit. Y. Muzychushun
 
01 Incapsulation
01 Incapsulation01 Incapsulation
01 Incapsulation
 
01 c# basics
01 c# basics01 c# basics
01 c# basics
 
Тестування при розробці програмного забезпечення. Unit Tests.
Тестування при розробці програмного забезпечення. Unit Tests.Тестування при розробці програмного забезпечення. Unit Tests.
Тестування при розробці програмного забезпечення. Unit Tests.
 
Theme20_ajax
Theme20_ajaxTheme20_ajax
Theme20_ajax
 
Prometheus. Масовий онлайн курс "Основи програмування". Лекція 7
Prometheus. Масовий онлайн курс "Основи програмування". Лекція 7Prometheus. Масовий онлайн курс "Основи програмування". Лекція 7
Prometheus. Масовий онлайн курс "Основи програмування". Лекція 7
 
Основнi моменти модульного тестування в Qt
Основнi моменти модульного тестування в QtОсновнi моменти модульного тестування в Qt
Основнi моменти модульного тестування в Qt
 
Advanced C#. Part 2
Advanced C#. Part 2Advanced C#. Part 2
Advanced C#. Part 2
 
Automated testing
Automated testingAutomated testing
Automated testing
 
08 Templates
08 Templates08 Templates
08 Templates
 
09 Object And Class Hierarchy
09 Object And Class Hierarchy09 Object And Class Hierarchy
09 Object And Class Hierarchy
 

Similar to Phpunit

Code driven testing -- oleksandr pavlyshak
Code driven testing -- oleksandr pavlyshakCode driven testing -- oleksandr pavlyshak
Code driven testing -- oleksandr pavlyshakIgor Bronovskyy
 
Prometheus. Масовий онлайн курс "Основи програмування". Лекція 5
Prometheus. Масовий онлайн курс "Основи програмування". Лекція 5Prometheus. Масовий онлайн курс "Основи програмування". Лекція 5
Prometheus. Масовий онлайн курс "Основи програмування". Лекція 5Nikita Pavliuchenko
 
Net framework і c# module 3
Net framework і c# module 3Net framework і c# module 3
Net framework і c# module 3Andrii Hladkyi
 
"Unit testing in AngularJS" Виктор Зозуляк
"Unit testing in AngularJS" Виктор Зозуляк"Unit testing in AngularJS" Виктор Зозуляк
"Unit testing in AngularJS" Виктор ЗозулякFwdays
 
Компютерне моделювання
Компютерне моделюванняКомпютерне моделювання
Компютерне моделюванняriyoksana1
 
Структура тест-кейсу та звіту про помилки.pptx
Структура тест-кейсу та звіту про помилки.pptxСтруктура тест-кейсу та звіту про помилки.pptx
Структура тест-кейсу та звіту про помилки.pptxssuser40c4fa
 
Net framework і c# module 8
Net framework і c# module 8Net framework і c# module 8
Net framework і c# module 8Andrii Hladkyi
 
[Knowledge Sharing] - Unit Testing by Pavlo Serdyuk (UKR)
[Knowledge Sharing] - Unit Testing by Pavlo Serdyuk (UKR)[Knowledge Sharing] - Unit Testing by Pavlo Serdyuk (UKR)
[Knowledge Sharing] - Unit Testing by Pavlo Serdyuk (UKR)Exoft LLC
 
[Knowledge Sharing] - Behavioral patterns by Pavlo Serdyuk (UKR)
[Knowledge Sharing] - Behavioral patterns by Pavlo Serdyuk (UKR)[Knowledge Sharing] - Behavioral patterns by Pavlo Serdyuk (UKR)
[Knowledge Sharing] - Behavioral patterns by Pavlo Serdyuk (UKR)Exoft LLC
 

Similar to Phpunit (20)

tsql
tsqltsql
tsql
 
Code driven testing -- oleksandr pavlyshak
Code driven testing -- oleksandr pavlyshakCode driven testing -- oleksandr pavlyshak
Code driven testing -- oleksandr pavlyshak
 
Code driven testing (UA)
Code driven testing (UA)Code driven testing (UA)
Code driven testing (UA)
 
Prometheus. Масовий онлайн курс "Основи програмування". Лекція 5
Prometheus. Масовий онлайн курс "Основи програмування". Лекція 5Prometheus. Масовий онлайн курс "Основи програмування". Лекція 5
Prometheus. Масовий онлайн курс "Основи програмування". Лекція 5
 
cpp-2013 #16 Automated testing
cpp-2013 #16 Automated testingcpp-2013 #16 Automated testing
cpp-2013 #16 Automated testing
 
Tdd, ти де?
Tdd, ти де?Tdd, ти де?
Tdd, ти де?
 
Net framework і c# module 3
Net framework і c# module 3Net framework і c# module 3
Net framework і c# module 3
 
пеценчук
пеценчукпеценчук
пеценчук
 
"Unit testing in AngularJS" Виктор Зозуляк
"Unit testing in AngularJS" Виктор Зозуляк"Unit testing in AngularJS" Виктор Зозуляк
"Unit testing in AngularJS" Виктор Зозуляк
 
ASP.Net MVC
ASP.Net MVCASP.Net MVC
ASP.Net MVC
 
Модулі Python
Модулі PythonМодулі Python
Модулі Python
 
Компютерне моделювання
Компютерне моделюванняКомпютерне моделювання
Компютерне моделювання
 
базовI структури алгоритму урок 4
базовI структури алгоритму урок 4базовI структури алгоритму урок 4
базовI структури алгоритму урок 4
 
Структура тест-кейсу та звіту про помилки.pptx
Структура тест-кейсу та звіту про помилки.pptxСтруктура тест-кейсу та звіту про помилки.pptx
Структура тест-кейсу та звіту про помилки.pptx
 
Clean code (UA)
Clean code (UA)Clean code (UA)
Clean code (UA)
 
Net framework і c# module 8
Net framework і c# module 8Net framework і c# module 8
Net framework і c# module 8
 
[Knowledge Sharing] - Unit Testing by Pavlo Serdyuk (UKR)
[Knowledge Sharing] - Unit Testing by Pavlo Serdyuk (UKR)[Knowledge Sharing] - Unit Testing by Pavlo Serdyuk (UKR)
[Knowledge Sharing] - Unit Testing by Pavlo Serdyuk (UKR)
 
L l13
L l13L l13
L l13
 
Oop - TTm
Oop - TTmOop - TTm
Oop - TTm
 
[Knowledge Sharing] - Behavioral patterns by Pavlo Serdyuk (UKR)
[Knowledge Sharing] - Behavioral patterns by Pavlo Serdyuk (UKR)[Knowledge Sharing] - Behavioral patterns by Pavlo Serdyuk (UKR)
[Knowledge Sharing] - Behavioral patterns by Pavlo Serdyuk (UKR)
 

Phpunit

  • 1. PHP Unit ОСНОВИ МОДУЛЬНОГО І ІНТЕГРАЦІЙНОГО ТЕСТУВАННЯ
  • 2. Типи тестування  Модульне(Unit testing) — тестування одного окремого модуля (метода).  Інтеграційне(Integration Testing) — тестування групи взаємодіючих модулів.  Системне (System Testing) — тестування системы вцілому.
  • 3. Опис модульного тестування Мета:  Ізолювати окремі частини програми і показати, що ці окремі модулі працездатні.  Можливість безболісно проводити рефакторінг  «Живий документ» тестованого модуля (можливість швидко розібратись з логікою модуля)  Перевірка якості коду модуля (всі можливі/неможливі вхідні/вихідні данні) Типи:  Тести стану (state based) – перевіряють, що викликаний метод обєкта обробився коректно, превіряючи стан тестованого обєкта після виклику метода.  Тести взаємодії (interaction tests) – тест в якому тестований обєкт виконує маніпуляції з другими обєктами. Приміняються тоді, коли потрібно переконатись, що тестований обєкт коректно взаємодіє з іншими обєктами.
  • 4. Зовнішня залежність в тестах Модульні тести: Використання mock/stub обєктів, замість прямого звязку з БД, або іншими зовнішніми системами. Інтеграційні тести: Використання прямих підключень і запитів до БД з використанням транзакцій, або до інших зовнішніх систем.
  • 5. Приклад модульного тесту Tender { public function checkDate($date){ if($date > date(‘d-m-Y’, time())){ return ‘success’; } else { return ‘error’; } } } TenderTest { public function testCheckDate() { $date = date(‘d-m-Y’, time()+3600); //null, another date format, date with spaces $result = (new Tender())->checkDate($date); $this->assertTrue($result == ‘success’); } }
  • 6. Data provider Dataprovider використовується для різних наборів вхідних данних. Метод, який являється DataProvider’ом, має повертати масив масивів, або обєкт. Метод, який являється тестом буде викликатись декілька раз з кожним масивом, в якості аргументів будуть передаватись вміст масиву. Ключові моменти для використання dataProvider: - dataProvider має бути статичним публічним методом. - dataProvider має повертати масив зібраних данних - тест має використовувати аннотацію @dataProvider, щоб вказати, який метод має використовуватись в якості dataProvider
  • 7. Приклад використання data provider Public static function dateProvider(){ return [ [date(‘d-m-Y’, time()), ‘error’], [date(‘d-m-Y’, time()+3600), ‘success’], [null, ‘error’] ]; } /** * @dataProvider dateProvider */ public function testCheckDate($date, $result) { $res = (new Tender())->checkDate($date); $this->assertTrue($res == $result); }
  • 8. Asserts (перевірки)  assertTrue($bool[, $message])  assertArrayHasKey($key, $array[,$message])  assertClassHasAttribute($attr. $className)  assertContains($needle, $array|$string|$integer)  assertDirectoryExist($path)  assertDirectoryReadable($path)  assertEmpty($val)  assertFileExist($pathToFile)  assertGreaterThan($val1, $val2)  assertInstanceOf($class, $object)  assertRegExp($pattern, $string)
  • 9. Приклад використання asserts public function testCreateDate() { $date = date(‘d-m-Y’,time()+3600); $res = (new Tender())→createDate($date); $message1 = ‘createDate() не повертає обєкт, классу Date()’; $message2 = ‘в классі Date() немає аттрибуту $formDate’; $message3 = ‘метод createDate() не відформатував $date’; $this→assertInstanceOf(Date(), $res, $message1); $this→assertClassHasAttribute(‘formatDate’, ‘Date’, $message2); $this→assertTrue($date != $res→formatDate, $message3) } public function createDate($date){ if($date > date(‘d-m-Y’, time())){ return new Date($date); } else { return null; } } Class Date{ public $formatDate; public function __constructor($date){ $this→formatDate = date(‘Y-m-d’, strtotime($date)); } }
  • 10. Залежності тестів  Producer – тестовий метод, котрий повертає значення, від яких залежать інші методи модуля.  Consumer – тестовий метод, котрий залежить від одного або більше методів (producer) і значень, які вони повертають.  Для позначенняя залежного метода, використовується анотація @depends   public function testEmpty(){  $stack = array();  $this->assertTrue(empty($stack));  return $stack;  }  /**  * @depends testEmpty  */  public function testPush(array $stack) {  array_push($stack, 'foo');  $this->assertEquals('foo', $stack[count($stack)-1]);  $this->assertFalse(empty($stack));  return $stack;  }  /**  * @depends testPush  */  public function testPop(array $stack)  {  $this->assertEquals('foo', array_pop($stack));  $this->assertTrue(empty($stack));  }  } 
  • 11. Тестування виключень (exception)  Метод який повертає exeption  public function returnException() {  $this->setException('InvalidArgException');  }  Перевірка exeption в тесті  /**  * @expectedException InvalidArgException<br>  */  public function testException() {  (new SomeClass())->returnException();  $this->assertTrue(true);  }
  • 12. Mock, Stub класи заглушки (дублери)  Коли потрібно використовувати класи дублери:  Необхідність можливості запуску тестів незалежно де (на машині любого розробника в любій ОС)  Коли результат запиту до БД/api нам стовідсотково відомий і нам не потрібно його перевіряти.  Низька швидкість виконання тестів з реальними обєктами (наприклад робота з БД, файламию поштовим сервером, сторонніми api)  Типи класів дублерів:  Dummy – обєкти котрі передаються в методиб але насправді не використовуються. В основному це параметри методів (якщо вони не впливають в тесті на те, що ми хочемо перевірити). Іноді це просто null.  Fake – це обєкти, котрі мають внутрішню реалізацію, але зазвичай вона урізана і їх не можна використовувати в готовому коді.  Stubs – обеспечують чітко зашиту відповідб на виклик під час тестування. Приміняються для заміни тих обєктів, які забезпечують тест вхідними данними. Також вони можуть зберігати в соб інформацію про виклики (наприклад параметри і кількість викликів).  Mocks – обєкти, котрі налаштовуються (наприклад специфічно під кожен тест) і дозволяють задавати очікування в вигляді свого роду специфікації викликів, які ми плануємо отримати.  Mock – використовується для тестів на поведінку обєкта.  Всі інші дублі використовуються для тестуванння стану обєкта після виклику метода.
  • 13. Методи по роботі з класами дублями (Mock)  public function getMock(  $originalClassName, // назва оригінального класу, для котрого буде створений Mock объект  $methods = array(), // масив методів які будуть замінені  array $arguments = array(), // аргументи, як передаються в конструктор  $mockClassName = '', // можна вказать імя Mock класа  $callOriginalConstructor = true, // відключення виклику конструктора  $callOriginalClone = true, // відключення виклику __clone()  $callAutoload = true // відключення виклику __autoload()  );  Якщо другим аргументом в getMock() передати null, тоді жоден метод не буде замінений.  Додаткові способи виклику Mock обєкта:  $mock = $this->getMockBuilder('MyClass')  ->setMethods(null)  ->setConstructorArgs(array())  ->setMockClassName('')  ->disableOriginalConstructor()  ->disableOriginalClone()  ->disableAutoload()  →getMock();  getMockClass() — створює Mock класс і повертає його назву у вигляді строки;  getMockForAbstractClass() — повертає Mock обєкт абстрактного класа, в котрому замінені всі абстрактні методи. 
  • 14. Очікування виклику метода  PHPUnit дозволяєє нам контролювати кількість і порядок викликів підмінених методів, для цього використовується метод expects()  public function test_process() {  $mock = $this->getMock('MyClass', array('getTemperature', 'getWord'));  $mock->expects($this->once())->method('getTemperature');  $mock->expects($this->once())->method('getWord');  $mock->process();  }  Результат виконання цього тесту буде успішним, якщо при виклику метода process() відбудеться одноразовий виклик двох вказаних методів: getTemperature(), getWord(). В такому випадку неважливий порядок виклику методів.  Для контроля порядка виклику методів в PHPUnit використовується друга конструкція — at().  public function test_process() {  $mock = $this->getMock('MyClass', array('getTemperature', 'getWord'));  $mock->expects($this->at(1))->method('getTemperature');  $mock->expects($this->at(0))->method('showWord');  $mock->process();  }  Окрім once() і at() для тестування очікування викликів в PHPUnit є також наступні конструкції: any(), never(), atLeastOnce() и exactly($count). 
  • 15. Перевизначення (заміна) методів Mock обєктів  Основною можливітю Mock обєктів, являється можливість заміни методів.  Для перевизначення методів використовується метод will():  $temperature = 20;  $mock→expects($this→once())→method('getTemperature')→will($this→returnValue($temperature));   Перевірка вказаних аргументів:  Ще одна корисна для тестування можливість Mock обєктів являється перевірка аргументів, вказанных при виклику подміненого метода, за допомогою конструкції with():   public function test_with_and_will_usage() {  $mock = $this->getMock('MyClass', array('getWord'));  $mock->expects($this->once())  ->method('getWord')  ->with($this->greaterThan(25))  ->will($this->returnValue('hot'));  $this->assertEquals('hot', $mock->getWord(30));  }  В якості аргументів метод with() може приймати такі самі конструкції, що і перевірка assertThat():  attribute(), anything(), arrayHasKey(), contains(), )fileExists(), greaterThan(), classHasAttribute(), classHasStaticAttribute(), hasAttribute(), isFalse(), isInstanceOf(), isNull(), isTrue(), isType(), matchesRegularExpression(), stringContains()    
  • 16. Приклад використання mock обєкта.  Class Tender{  public function getCategories(){  return (new Category)→getList(); //request to DB  }  public function checkCategory($category){  return in_array($category, $this->getCategories());  }  }  private $_categories = [1,2,3,4]  public function testCheckCategories(){  $mock = $this→getMock(‘Tender’, [‘getCategories’]);  $this→assertInstanceOf(‘Tender’, $mock);  $mock→expects($this→once())  →method(‘getCategories’)→returnValue($this→  ->returnValue($this->_categories);   }
  • 17. Тестове оточення (fixtures).  Так як після завершення тесту всім змінним потрібно повернути попередні значення, створюється тестове оточення (fixture).  Для її створення використовуються методи:  До того як почне виконувтись тест, викликається метод setUp();  Як тільки тест завершиться, викликається метод tearDown();  Також є інші методи, які викликаються в такій послідовності:  setUpBeforeClass()  setUp();  assertPreConditions();  testOne(); // тест  assertPostConditions();  tearDown();
  • 18. Транзакції в тестуванні  Транзакції зазвичай використовуються в інтеграційних тестах, в модульних використовуюься mock обєкти для звязку з БД.  public function setUp()  {  parent::setUp();  DB::beginTransaction();  }   public function tearDown()  {  DB::rollBack();  parent::tearDown();  }
  • 19. MVC  Модель — містить бізнес-логіку додатку. Включає методи виборки, обробки і надання конкретних данних, що зазвичай робить її дуже великою, це нормально.   Вид — використовується для відображення данних, отриманих з контроллера і моделі.  Вид містить HTML и невеликі вставки PHP-кода для форматування і відображення данних.  Не повинен напряму звертатись до БД.  Не повинен працювати з данними, отриманими з запита користувача.  Може напряму звертатись властивостей і методів контролера чи моделі, для отримання готових данних.   Контролер — звязок моделі і виду. Контроллер відповідає за обробку запросів користувача. Контроллер не повинен містити SQL-запросів.  Контроллер не повинен містити HTML.  В гарно спроектованому MVC-додатку контролери зазвичай дуже маленькі і містять лише декілка десятків строк коду.  Модели, навпаки, дуже товсті і містять більшу частину кода, повязану з
  • 20. Рефакторінг  TenderController{  public function store(Request $request){  $data = $request→all();  if(!empty($data[‘some’])){  $data[‘result’] = true;  }  if(!empty($data[‘some2’])){  $data[‘result2’] = false;  }  $tender = Tender::where(‘result’, $data[‘result’])  ->orWhere(‘result2’, $data[‘result2’])  ->orderBy('updated_at', 'asc')→get();   if($tender→status == ‘lalala’){  return false;  } elseif($tender→status == ‘666’) {  return false;  } else {  return true;  }  }  }  TenderController{  public function store(Request $request, Tender $model){  $data = $request→all();  $data = $model->checkData($data);  $tender = $model->getTender($data);  return $tender->checkStatus()  }  }  Model/Tender{  public function checkData($data){  if(!empty($data[‘some’])){  $data[‘result’] = true;  }  if(!empty($data[‘some2’])){  $data[‘result2’] = false;  }  return $data  }  public function getTender(){  return self::where(‘result’, $data[‘result’])  ->orWhere(‘result2’, $data[‘result2’])  ->orderBy('updated_at', 'asc')→get()  }  public function checkStatus(){  if($this→status == ‘lalala’){  return false;  } elseif($this→status == ‘666’) {  return false;  } else {  return true;  }  }  }