SlideShare a Scribd company logo
1 of 32
TTD in ZF2

Пространства имен

Замыкания

ZF2 поставляемые в стандартной
поставке тесты

Поддержка нового phpunit 3.5
# ls
Bootstrap.php docs phpunit.xml resources runtests.sh
TestConfiguration.php.dist Zend
# cat TestConfiguration.php.dist
/**
* Zend_Db_Adapter_Sqlsrv
* Note: Make sure that you create the "test" database and set a
* username and password
*
*/
define('TESTS_ZEND_DB_ADAPTER_SQLSRV_ENABLED', false);
define('TESTS_ZEND_DB_ADAPTER_SQLSRV_HOSTNAME', '');
define('TESTS_ZEND_DB_ADAPTER_SQLSRV_USERNAME', null);
define('TESTS_ZEND_DB_ADAPTER_SQLSRV_PASSWORD', null);
define('TESTS_ZEND_DB_ADAPTER_SQLSRV_DATABASE', 'test');
Стукрутра папок
- library - модульные
- application - интеграционные
+ functional - функциональные
+ perfomance — функциональные
Тестировать не нужно
- Zend Framework
- Doctrine / Propel
- Jquery / Prototype / Dojo
- Symphony DI / Crafty / DI
- all extenal libraries ...
Тестировать нужно
- Абстрактные классы и интефейсы
- Базовые компонеты
- Магическую инициализацию
- Любые не очевидные вещи
DRY – не повторяться
1 тест – 1 проверка
Хороший тест – 5 строк
Если что-то протестировано, не
тетсируем это снова
Крохобор (The Nitpicker) Уклонист (The Dodger)
Гигант (Giant) Любитель Порядка (The Sequencer) Счётчик (The Enumerator)
Избранный (The One) Тормоз (The Slow Poke) ...
Основные принципы
Class => ClassName + Test.php
Namespace => Test
PhpDoc => bugNumber
_files — для тестовых файлов
_fixtures — для фикстур
phpunit.xml
@cover Class::method
Организация тестов
<phpunit colors="true" bootstrap="./bootstrap.php">
<testsuite name="Test/Library">
<directory>./library/</directory>
</testsuite>
<testsuite name="Test/Application">
<directory>./application/</directory>
</testsuite>
<testsuite name="Test/Functional">
<directory>./functional/</directory>
</testsuite>
<logging>
<log type="coverage-html" target="/tmp" charset="UTF-8"
yui="true" highlight="false"
lowUpperBound="35" highLowerBound="70"/>
</logging>
</phpunit>
/test/tests/application/controllers# cat IndexControllerTest.php
namespace Test;
class IndexController extends ZendTestPHPUnitControllerTestCase
{
public $bootstrap = '../../bootstrap.php';
/**
* @group Bug123
* @cover IndexController::indexAction
*/
public function testIndexAction()
{
$this->dispatch('/');
$this->assertController("index");
$this->assertAction("index");
}
}
Тестирование Controller
Тестирование Controller
class IndexController extends ZendTestPHPUnitControllerTestCase
public function testIndexAction()
$this->dispatch('/');
$this->assertController("index");
$this->assertAction("index");
$this->assertQueryContentContains('#content', 'Hello Im here');
$this->assertQueryContentContains('div.content', 'Hello Im here');
$this->assertQueryContentContains('body .content', 'Hello Im here');
$this->assertQueryCount('#categories li', 3);
<?php
class IndexController extends AbstractController
public function indexAction()
$this->view->hello = 'Im here';
Тестирование Controller::init
<?php
abstract class AbstractController extends ZendControllerAction
{
public function init()
{
$this->_helper->contextSwitch()
->addActionContext('index', array('xml', 'json'))
->setAutoJsonSerialization(true)
->initContext();
$this->view->categories = new ApplicationModelCategoryMapper();
}
}
Тестирование Controller:init
class AbstractController extends ZendTestPHPUnitControllerTestCase
public function testInitContext()
$controller = new AbstractControllerStub($this->getRequest(),
$this->getResponse());
$this->assertEquals(
$controller->getHelper('ContextSwitch')->getActionContexts('index'),
array('xml', 'json'));
public function testInitCategories()
$controller = new AbstractControllerStub($this->getRequest(),
$this->getResponse());
$this->assertType('ApplicationModelCategoryMapper',
$controller->view->categories);
Тестирование Form
<?php
namespace ApplicationForm;
class Registration extends ZendFormForm
public function init()
$this->addElement('text', 'username');
$this->addElement('text', 'password');
$this->addElement('text', 'password_retype');
public function isValid($params)
$result = parent::isValid($params);
if ($this->getValue('password')!=$this->getValue('password_retype')) {
return false;
}
return $result;
Тестирование Form
class Registration extends PHPUnit_Framework_TestCase
public function testValidate()
$form = new ApplicationFormRegistration;
$this->assertTrue($form->isValid(array(
'username' => 'test',
'password' => '123',
'password_retype' => '123',
)));
public function testValidateFail()
$form = new ApplicationFormRegistration;
$this->assertFalse($form->isValid(array(
'username' => 'test',
'password' => '123',
'password_retype' => '1234',
)));
Архитектура
→ getConnection
→ getDataSet
→ createDbTableDataSet
→ createDbTable
→ createDbRowset
Тестирование DbTable
$categories = new ApplicationModelDbTableCategories($this->getAdapter());
$categories->insert(array('id'=>4, 'name'=>'test'));
$this->assertDataSetsEqual(
$this->createFlatXmlDataSet("_fixtures/categoriesInsert.xml"),
$this->createDbTableDataSet(array($categories))
);
Тестирование DbTable
class CategoriesTest extends ZendTestPHPUnitDatabaseTestCase
public function getConnection()
$application = new Application (_ENV, _PATH . '/configs/application.ini');
$application->bootstrap();
$resource = $application->getBootstrap()->getPluginResource('db');
return $this->createZendDbConnection($resource->getDbAdapter(), 'any');
public function getDataSet()
return $this->createFlatXMLDataSet(__DIR__ . '/_fixtures/categories.xml');
public function testFecthAll()
$categories = new ApplicationModelDbTableCategories($this->getAdapter());
$rowset = $categories->fetchAllOrdered();
$this->assertEquals(count($rowset), 3);
Тестирование DbTable
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<categories id="1" name="cat1" />
<categories id="3" name="cat3" />
<categories id="2" name="cat2" />
</dataset>
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<categories id="1" name="cat1" />
<categories id="3" name="cat3" />
<categories id="2" name="cat2" />
<categories id="4" name="test" />
</dataset>
Тестирование Mapper
1. Использует сервис/сервисы
2. Используется моделями
3. Содержит код
setTable/getTable/__construct/init
которые идентичны и миргурируют
из одного маппера в другой
+ есть еще внешние источники
данных SOAP/XML-RPC/REST/RSS
Тестирование Mapper
<?php
namespace ApplicationModel;
class XXXMapper
{
protected $_table = null;
protected $_defaultServiceName = '';
public function __construct(DbTable $table=null)
public function getTable()
public function setTable(DbTable $table)
…
}
Тестирование Mapper

Выделить общий класс
AbstractMapper

Выделить интерфейс для сервисов

Наследовать все мапперы от
абстрактного

Имплементировать интерфейс
Service в DbTable
Тестирование Mapper
<?php
namespace ApplicationModel;
class AbstractMapper
{
protected $_service = null;
protected $_defaultServiceName = '';
public function __construct(Service $service=null)
{
if (is_null($service)) {
$name = $this->_defaultServiceName;
$this->setService(new $name);
} else {
$this->setService($this->_service = $service);
}
}
public function getService()
public function setService(Service $service)
}
Тестирование Mapper

Создаем реализации

Складываем в подпапку _files в
текущей директории
__Construct / Abstract class / Interface
<?php
namespace Test;
class AbstractMapperMockAutoload extends ApplicationModelAbstractMapper
{
protected $_defaultServiceName = 'TestServiceMock';
}
Тестирование Mapper
class AbstractMapperTest extends PHPUnit_Framework_TestCase
public function testInit()
$mock = new AbstractMapperMockAutoload();
$this->assertType('TestServiceMock', $mock->getService());
public function testInitFail()
try {
$mock = new AbstractMapperMock();
} catch (Exception $e) {
return ;
}
$this->fail('An expected exception has not been raised.');
public function testSet()
$mock = new AbstractMapperMockAutoload();
$mock->setService(new ServiceMock());
$this->assertType('TestServiceMock', $mock->getService());
Тестирование Selenium
Selenium RC
Selenium IDE
Selenium GRID
Тестирование Selenium
Тестирование Selenium
Native = left
<div id=”left”> <input name='left'>
Xpath = //div[@id='left']
<div id=”left”>
Css =
css=ul#recordlist li:nth-child(4)
css=input[name='continue'][type='button']
css=a[id^='id_prefix_']
css=a:contains('Log Out')
Тестирование Selenium
class Example extends PHPUnit_Extensions_SeleniumTestCase
{
protected $captureScreenshotOnFailure = TRUE;
protected $screenshotPath = '~/conf/public/screenshots';
protected $screenshotUrl = 'http://conf.local/screenshots';
protected function setUp()
{
$this->setBrowser("*chrome");
$this->setBrowserUrl("http://conf.local/");
}
public function testMyTestCase()
{
$this->open("index/index");
$this->assertEquals("index", $this->getText("content"));
}
}
Тестирование Selenium
public function testAjaxLoading()
{
$this->open("/index/index/");
$this->assertEquals("index", $this->getText("content"));
$this->click("showIndexInAjax");
for ($second = 0; ; $second++) {
if ($second >= 60) $this->fail("timeout");
try {
if ("Im here" == $this->getText("content")) break;
} catch (Exception $e) {}
sleep(1);
}
$this->assertEquals("Im here", $this->getText("content"));
}
Тестирование Selenium
class IndexController extends PHPUnit_Extensions_SeleniumTestCase
{
public function testHighlight()
{
$this->open("/index/index/");
$this->mouseOver("//div[@id='left']/li");
$this->assertEquals("rgb(255, 0, 0)", $this->getEval(
"this.findEffectiveStyleProperty(this.page()
.findElement("//div[@id='left']/li"),
'backgroundColor')"));
}
Тестирование Selenium
Вопросы ?

More Related Content

What's hot

2km Workshop: Desenvolvimento ágil com o CakePHP
2km Workshop: Desenvolvimento ágil com o CakePHP2km Workshop: Desenvolvimento ágil com o CakePHP
2km Workshop: Desenvolvimento ágil com o CakePHPCarlos Pires
 
Aller plus loin avec Doctrine2
Aller plus loin avec Doctrine2Aller plus loin avec Doctrine2
Aller plus loin avec Doctrine2André Tapia
 
from new class and dependency injection to PSR-11 and Auto-wiring
from new class and dependency injection to PSR-11 and Auto-wiringfrom new class and dependency injection to PSR-11 and Auto-wiring
from new class and dependency injection to PSR-11 and Auto-wiringMilad Arabi
 
Quiz Component For Joomla
Quiz Component For JoomlaQuiz Component For Joomla
Quiz Component For Joomlaguestebb21a
 
Working With Ajax Frameworks
Working With Ajax FrameworksWorking With Ajax Frameworks
Working With Ajax FrameworksJonathan Snook
 
Twig, los mejores trucos y técnicas avanzadas
Twig, los mejores trucos y técnicas avanzadasTwig, los mejores trucos y técnicas avanzadas
Twig, los mejores trucos y técnicas avanzadasJavier Eguiluz
 
KvZ Web Tasarım Hizmetleri
KvZ Web Tasarım HizmetleriKvZ Web Tasarım Hizmetleri
KvZ Web Tasarım HizmetleriAhmet Öztaş
 
Dennis zapana perez
Dennis zapana perezDennis zapana perez
Dennis zapana perezdennis_elvis
 
Drupal Cms Prezentace
Drupal Cms PrezentaceDrupal Cms Prezentace
Drupal Cms PrezentaceTomáš Kafka
 
Php codigos interfaces fredy guzman cusihunca
Php codigos interfaces   fredy guzman cusihuncaPhp codigos interfaces   fredy guzman cusihunca
Php codigos interfaces fredy guzman cusihuncaTigger_Fred
 
Assalamualaykum warahmatullahi wabarakatuu
Assalamualaykum warahmatullahi wabarakatuuAssalamualaykum warahmatullahi wabarakatuu
Assalamualaykum warahmatullahi wabarakatuuiswan_di
 

What's hot (19)

jQuery for beginners
jQuery for beginnersjQuery for beginners
jQuery for beginners
 
2km Workshop: Desenvolvimento ágil com o CakePHP
2km Workshop: Desenvolvimento ágil com o CakePHP2km Workshop: Desenvolvimento ágil com o CakePHP
2km Workshop: Desenvolvimento ágil com o CakePHP
 
Aller plus loin avec Doctrine2
Aller plus loin avec Doctrine2Aller plus loin avec Doctrine2
Aller plus loin avec Doctrine2
 
Iteratory
IteratoryIteratory
Iteratory
 
from new class and dependency injection to PSR-11 and Auto-wiring
from new class and dependency injection to PSR-11 and Auto-wiringfrom new class and dependency injection to PSR-11 and Auto-wiring
from new class and dependency injection to PSR-11 and Auto-wiring
 
Quiz Component For Joomla
Quiz Component For JoomlaQuiz Component For Joomla
Quiz Component For Joomla
 
Wek14 mysql 2
Wek14 mysql 2Wek14 mysql 2
Wek14 mysql 2
 
Working With Ajax Frameworks
Working With Ajax FrameworksWorking With Ajax Frameworks
Working With Ajax Frameworks
 
Index2
Index2Index2
Index2
 
Twig, los mejores trucos y técnicas avanzadas
Twig, los mejores trucos y técnicas avanzadasTwig, los mejores trucos y técnicas avanzadas
Twig, los mejores trucos y técnicas avanzadas
 
KvZ Web Tasarım Hizmetleri
KvZ Web Tasarım HizmetleriKvZ Web Tasarım Hizmetleri
KvZ Web Tasarım Hizmetleri
 
Dennis zapana perez
Dennis zapana perezDennis zapana perez
Dennis zapana perez
 
Testování prakticky
Testování praktickyTestování prakticky
Testování prakticky
 
Introducción a Bolt
Introducción a BoltIntroducción a Bolt
Introducción a Bolt
 
Drupal Cms Prezentace
Drupal Cms PrezentaceDrupal Cms Prezentace
Drupal Cms Prezentace
 
es6.concurrency()
es6.concurrency()es6.concurrency()
es6.concurrency()
 
Php codigos interfaces fredy guzman cusihunca
Php codigos interfaces   fredy guzman cusihuncaPhp codigos interfaces   fredy guzman cusihunca
Php codigos interfaces fredy guzman cusihunca
 
Silex al límite
Silex al límiteSilex al límite
Silex al límite
 
Assalamualaykum warahmatullahi wabarakatuu
Assalamualaykum warahmatullahi wabarakatuuAssalamualaykum warahmatullahi wabarakatuu
Assalamualaykum warahmatullahi wabarakatuu
 

Viewers also liked

1000 миллисекунд из жизни Magento
1000 миллисекунд из жизни Magento1000 миллисекунд из жизни Magento
1000 миллисекунд из жизни MagentoMagecom Ukraine
 
Мобильные клиенты интернет-магазинов
Мобильные клиенты интернет-магазиновМобильные клиенты интернет-магазинов
Мобильные клиенты интернет-магазиновMagecom Ukraine
 
NoSQL и Zend Framework (Никита Грошин)
NoSQL и Zend Framework (Никита Грошин)NoSQL и Zend Framework (Никита Грошин)
NoSQL и Zend Framework (Никита Грошин)zfconfua
 
Все дороги ведут в Checkout
Все дороги ведут в CheckoutВсе дороги ведут в Checkout
Все дороги ведут в CheckoutMagecom Ukraine
 
Эволюция ZF: архитектура, шаблоны, рефакторинг
Эволюция ZF: архитектура, шаблоны, рефакторингЭволюция ZF: архитектура, шаблоны, рефакторинг
Эволюция ZF: архитектура, шаблоны, рефакторингzfconfua
 
Применение компонент-ориентированной архитектуры для написания Magento Extens...
Применение компонент-ориентированной архитектуры для написания Magento Extens...Применение компонент-ориентированной архитектуры для написания Magento Extens...
Применение компонент-ориентированной архитектуры для написания Magento Extens...Magecom Ukraine
 
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...zfconfua
 
Применение Scrum и Kanban для разработки web-приложений
Применение Scrum и Kanban для разработки web-приложенийПрименение Scrum и Kanban для разработки web-приложений
Применение Scrum и Kanban для разработки web-приложенийKirill Klimov
 
Doctrine 2
Doctrine 2Doctrine 2
Doctrine 2zfconfua
 
Система рендеринга в Magento
Система рендеринга в MagentoСистема рендеринга в Magento
Система рендеринга в MagentoMagecom Ukraine
 
Реализация шаблонов корпоративных приложений в Magento
Реализация шаблонов корпоративных приложений в MagentoРеализация шаблонов корпоративных приложений в Magento
Реализация шаблонов корпоративных приложений в MagentoMagecom Ukraine
 
Преимущества использования полнотекстового поиска в интернет-магазинах
Преимущества использования полнотекстового поиска в интернет-магазинахПреимущества использования полнотекстового поиска в интернет-магазинах
Преимущества использования полнотекстового поиска в интернет-магазинахMagecom Ukraine
 
Встречайте Zend Framework 2.0
Встречайте Zend Framework 2.0Встречайте Zend Framework 2.0
Встречайте Zend Framework 2.0zfconfua
 
Ключ успеха – процесс или продукт?
Ключ успеха – процесс или продукт?Ключ успеха – процесс или продукт?
Ключ успеха – процесс или продукт?Magecom Ukraine
 
Управление продуктом в стиле Magento Unified Process
Управление продуктом в стиле Magento Unified ProcessУправление продуктом в стиле Magento Unified Process
Управление продуктом в стиле Magento Unified ProcessMagecom Ukraine
 
Применение TDD при разработке веб-сервисов
Применение TDD при разработке веб-сервисовПрименение TDD при разработке веб-сервисов
Применение TDD при разработке веб-сервисовMagecom Ukraine
 
Индексирование в Magento
Индексирование в MagentoИндексирование в Magento
Индексирование в MagentoMagecom Ukraine
 
NoSQL и Zend Framework (Ростислав Михайлив)
NoSQL и Zend Framework (Ростислав Михайлив)NoSQL и Zend Framework (Ростислав Михайлив)
NoSQL и Zend Framework (Ростислав Михайлив)zfconfua
 

Viewers also liked (18)

1000 миллисекунд из жизни Magento
1000 миллисекунд из жизни Magento1000 миллисекунд из жизни Magento
1000 миллисекунд из жизни Magento
 
Мобильные клиенты интернет-магазинов
Мобильные клиенты интернет-магазиновМобильные клиенты интернет-магазинов
Мобильные клиенты интернет-магазинов
 
NoSQL и Zend Framework (Никита Грошин)
NoSQL и Zend Framework (Никита Грошин)NoSQL и Zend Framework (Никита Грошин)
NoSQL и Zend Framework (Никита Грошин)
 
Все дороги ведут в Checkout
Все дороги ведут в CheckoutВсе дороги ведут в Checkout
Все дороги ведут в Checkout
 
Эволюция ZF: архитектура, шаблоны, рефакторинг
Эволюция ZF: архитектура, шаблоны, рефакторингЭволюция ZF: архитектура, шаблоны, рефакторинг
Эволюция ZF: архитектура, шаблоны, рефакторинг
 
Применение компонент-ориентированной архитектуры для написания Magento Extens...
Применение компонент-ориентированной архитектуры для написания Magento Extens...Применение компонент-ориентированной архитектуры для написания Magento Extens...
Применение компонент-ориентированной архитектуры для написания Magento Extens...
 
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
 
Применение Scrum и Kanban для разработки web-приложений
Применение Scrum и Kanban для разработки web-приложенийПрименение Scrum и Kanban для разработки web-приложений
Применение Scrum и Kanban для разработки web-приложений
 
Doctrine 2
Doctrine 2Doctrine 2
Doctrine 2
 
Система рендеринга в Magento
Система рендеринга в MagentoСистема рендеринга в Magento
Система рендеринга в Magento
 
Реализация шаблонов корпоративных приложений в Magento
Реализация шаблонов корпоративных приложений в MagentoРеализация шаблонов корпоративных приложений в Magento
Реализация шаблонов корпоративных приложений в Magento
 
Преимущества использования полнотекстового поиска в интернет-магазинах
Преимущества использования полнотекстового поиска в интернет-магазинахПреимущества использования полнотекстового поиска в интернет-магазинах
Преимущества использования полнотекстового поиска в интернет-магазинах
 
Встречайте Zend Framework 2.0
Встречайте Zend Framework 2.0Встречайте Zend Framework 2.0
Встречайте Zend Framework 2.0
 
Ключ успеха – процесс или продукт?
Ключ успеха – процесс или продукт?Ключ успеха – процесс или продукт?
Ключ успеха – процесс или продукт?
 
Управление продуктом в стиле Magento Unified Process
Управление продуктом в стиле Magento Unified ProcessУправление продуктом в стиле Magento Unified Process
Управление продуктом в стиле Magento Unified Process
 
Применение TDD при разработке веб-сервисов
Применение TDD при разработке веб-сервисовПрименение TDD при разработке веб-сервисов
Применение TDD при разработке веб-сервисов
 
Индексирование в Magento
Индексирование в MagentoИндексирование в Magento
Индексирование в Magento
 
NoSQL и Zend Framework (Ростислав Михайлив)
NoSQL и Zend Framework (Ростислав Михайлив)NoSQL и Zend Framework (Ростислав Михайлив)
NoSQL и Zend Framework (Ростислав Михайлив)
 

Юнит тестирование в Zend Framework 2.0

  • 2.  Пространства имен  Замыкания  ZF2 поставляемые в стандартной поставке тесты  Поддержка нового phpunit 3.5
  • 3. # ls Bootstrap.php docs phpunit.xml resources runtests.sh TestConfiguration.php.dist Zend # cat TestConfiguration.php.dist /** * Zend_Db_Adapter_Sqlsrv * Note: Make sure that you create the "test" database and set a * username and password * */ define('TESTS_ZEND_DB_ADAPTER_SQLSRV_ENABLED', false); define('TESTS_ZEND_DB_ADAPTER_SQLSRV_HOSTNAME', ''); define('TESTS_ZEND_DB_ADAPTER_SQLSRV_USERNAME', null); define('TESTS_ZEND_DB_ADAPTER_SQLSRV_PASSWORD', null); define('TESTS_ZEND_DB_ADAPTER_SQLSRV_DATABASE', 'test');
  • 4. Стукрутра папок - library - модульные - application - интеграционные + functional - функциональные + perfomance — функциональные
  • 5. Тестировать не нужно - Zend Framework - Doctrine / Propel - Jquery / Prototype / Dojo - Symphony DI / Crafty / DI - all extenal libraries ...
  • 6. Тестировать нужно - Абстрактные классы и интефейсы - Базовые компонеты - Магическую инициализацию - Любые не очевидные вещи
  • 7. DRY – не повторяться 1 тест – 1 проверка Хороший тест – 5 строк Если что-то протестировано, не тетсируем это снова Крохобор (The Nitpicker) Уклонист (The Dodger) Гигант (Giant) Любитель Порядка (The Sequencer) Счётчик (The Enumerator) Избранный (The One) Тормоз (The Slow Poke) ... Основные принципы
  • 8. Class => ClassName + Test.php Namespace => Test PhpDoc => bugNumber _files — для тестовых файлов _fixtures — для фикстур phpunit.xml @cover Class::method Организация тестов
  • 9. <phpunit colors="true" bootstrap="./bootstrap.php"> <testsuite name="Test/Library"> <directory>./library/</directory> </testsuite> <testsuite name="Test/Application"> <directory>./application/</directory> </testsuite> <testsuite name="Test/Functional"> <directory>./functional/</directory> </testsuite> <logging> <log type="coverage-html" target="/tmp" charset="UTF-8" yui="true" highlight="false" lowUpperBound="35" highLowerBound="70"/> </logging> </phpunit>
  • 10. /test/tests/application/controllers# cat IndexControllerTest.php namespace Test; class IndexController extends ZendTestPHPUnitControllerTestCase { public $bootstrap = '../../bootstrap.php'; /** * @group Bug123 * @cover IndexController::indexAction */ public function testIndexAction() { $this->dispatch('/'); $this->assertController("index"); $this->assertAction("index"); } } Тестирование Controller
  • 11. Тестирование Controller class IndexController extends ZendTestPHPUnitControllerTestCase public function testIndexAction() $this->dispatch('/'); $this->assertController("index"); $this->assertAction("index"); $this->assertQueryContentContains('#content', 'Hello Im here'); $this->assertQueryContentContains('div.content', 'Hello Im here'); $this->assertQueryContentContains('body .content', 'Hello Im here'); $this->assertQueryCount('#categories li', 3); <?php class IndexController extends AbstractController public function indexAction() $this->view->hello = 'Im here';
  • 12. Тестирование Controller::init <?php abstract class AbstractController extends ZendControllerAction { public function init() { $this->_helper->contextSwitch() ->addActionContext('index', array('xml', 'json')) ->setAutoJsonSerialization(true) ->initContext(); $this->view->categories = new ApplicationModelCategoryMapper(); } }
  • 13. Тестирование Controller:init class AbstractController extends ZendTestPHPUnitControllerTestCase public function testInitContext() $controller = new AbstractControllerStub($this->getRequest(), $this->getResponse()); $this->assertEquals( $controller->getHelper('ContextSwitch')->getActionContexts('index'), array('xml', 'json')); public function testInitCategories() $controller = new AbstractControllerStub($this->getRequest(), $this->getResponse()); $this->assertType('ApplicationModelCategoryMapper', $controller->view->categories);
  • 14. Тестирование Form <?php namespace ApplicationForm; class Registration extends ZendFormForm public function init() $this->addElement('text', 'username'); $this->addElement('text', 'password'); $this->addElement('text', 'password_retype'); public function isValid($params) $result = parent::isValid($params); if ($this->getValue('password')!=$this->getValue('password_retype')) { return false; } return $result;
  • 15. Тестирование Form class Registration extends PHPUnit_Framework_TestCase public function testValidate() $form = new ApplicationFormRegistration; $this->assertTrue($form->isValid(array( 'username' => 'test', 'password' => '123', 'password_retype' => '123', ))); public function testValidateFail() $form = new ApplicationFormRegistration; $this->assertFalse($form->isValid(array( 'username' => 'test', 'password' => '123', 'password_retype' => '1234', )));
  • 17. → getConnection → getDataSet → createDbTableDataSet → createDbTable → createDbRowset Тестирование DbTable $categories = new ApplicationModelDbTableCategories($this->getAdapter()); $categories->insert(array('id'=>4, 'name'=>'test')); $this->assertDataSetsEqual( $this->createFlatXmlDataSet("_fixtures/categoriesInsert.xml"), $this->createDbTableDataSet(array($categories)) );
  • 18. Тестирование DbTable class CategoriesTest extends ZendTestPHPUnitDatabaseTestCase public function getConnection() $application = new Application (_ENV, _PATH . '/configs/application.ini'); $application->bootstrap(); $resource = $application->getBootstrap()->getPluginResource('db'); return $this->createZendDbConnection($resource->getDbAdapter(), 'any'); public function getDataSet() return $this->createFlatXMLDataSet(__DIR__ . '/_fixtures/categories.xml'); public function testFecthAll() $categories = new ApplicationModelDbTableCategories($this->getAdapter()); $rowset = $categories->fetchAllOrdered(); $this->assertEquals(count($rowset), 3);
  • 19. Тестирование DbTable <?xml version="1.0" encoding="UTF-8"?> <dataset> <categories id="1" name="cat1" /> <categories id="3" name="cat3" /> <categories id="2" name="cat2" /> </dataset> <?xml version="1.0" encoding="UTF-8"?> <dataset> <categories id="1" name="cat1" /> <categories id="3" name="cat3" /> <categories id="2" name="cat2" /> <categories id="4" name="test" /> </dataset>
  • 20. Тестирование Mapper 1. Использует сервис/сервисы 2. Используется моделями 3. Содержит код setTable/getTable/__construct/init которые идентичны и миргурируют из одного маппера в другой + есть еще внешние источники данных SOAP/XML-RPC/REST/RSS
  • 21. Тестирование Mapper <?php namespace ApplicationModel; class XXXMapper { protected $_table = null; protected $_defaultServiceName = ''; public function __construct(DbTable $table=null) public function getTable() public function setTable(DbTable $table) … }
  • 22. Тестирование Mapper  Выделить общий класс AbstractMapper  Выделить интерфейс для сервисов  Наследовать все мапперы от абстрактного  Имплементировать интерфейс Service в DbTable
  • 23. Тестирование Mapper <?php namespace ApplicationModel; class AbstractMapper { protected $_service = null; protected $_defaultServiceName = ''; public function __construct(Service $service=null) { if (is_null($service)) { $name = $this->_defaultServiceName; $this->setService(new $name); } else { $this->setService($this->_service = $service); } } public function getService() public function setService(Service $service) }
  • 24. Тестирование Mapper  Создаем реализации  Складываем в подпапку _files в текущей директории __Construct / Abstract class / Interface <?php namespace Test; class AbstractMapperMockAutoload extends ApplicationModelAbstractMapper { protected $_defaultServiceName = 'TestServiceMock'; }
  • 25. Тестирование Mapper class AbstractMapperTest extends PHPUnit_Framework_TestCase public function testInit() $mock = new AbstractMapperMockAutoload(); $this->assertType('TestServiceMock', $mock->getService()); public function testInitFail() try { $mock = new AbstractMapperMock(); } catch (Exception $e) { return ; } $this->fail('An expected exception has not been raised.'); public function testSet() $mock = new AbstractMapperMockAutoload(); $mock->setService(new ServiceMock()); $this->assertType('TestServiceMock', $mock->getService());
  • 28. Тестирование Selenium Native = left <div id=”left”> <input name='left'> Xpath = //div[@id='left'] <div id=”left”> Css = css=ul#recordlist li:nth-child(4) css=input[name='continue'][type='button'] css=a[id^='id_prefix_'] css=a:contains('Log Out')
  • 29. Тестирование Selenium class Example extends PHPUnit_Extensions_SeleniumTestCase { protected $captureScreenshotOnFailure = TRUE; protected $screenshotPath = '~/conf/public/screenshots'; protected $screenshotUrl = 'http://conf.local/screenshots'; protected function setUp() { $this->setBrowser("*chrome"); $this->setBrowserUrl("http://conf.local/"); } public function testMyTestCase() { $this->open("index/index"); $this->assertEquals("index", $this->getText("content")); } }
  • 30. Тестирование Selenium public function testAjaxLoading() { $this->open("/index/index/"); $this->assertEquals("index", $this->getText("content")); $this->click("showIndexInAjax"); for ($second = 0; ; $second++) { if ($second >= 60) $this->fail("timeout"); try { if ("Im here" == $this->getText("content")) break; } catch (Exception $e) {} sleep(1); } $this->assertEquals("Im here", $this->getText("content")); }
  • 31. Тестирование Selenium class IndexController extends PHPUnit_Extensions_SeleniumTestCase { public function testHighlight() { $this->open("/index/index/"); $this->mouseOver("//div[@id='left']/li"); $this->assertEquals("rgb(255, 0, 0)", $this->getEval( "this.findEffectiveStyleProperty(this.page() .findElement("//div[@id='left']/li"), 'backgroundColor')")); }