Написание автоматических тестов и среда phpUnit PHP


Оглавление (нажмите, чтобы открыть):

Инструмент для автоматического создания тестов PHPUnit?

Мне было интересно — есть ли инструмент, который будет смотреть на мой PHP-код и автоматически генерировать для него тест PHPUnit? Или есть ли такой инструмент для любого другого языка, который я мог бы переносить на PHP?

Я не говорю о создании скелета. Я думал, что будет возможно, чтобы инструмент мог смотреть на токенизированный PHP и определять пути кода через метод, а затем автоматически генерировать тест для каждого пути кода, создавая mocks и устанавливая «ожидающие» вызовы по мере необходимости.

Даже если нет инструмента, который в настоящее время это делает, может ли такая задача быть осуществимой или я что-то не замечаю?

Оказывается, нет инструмента, который делает это в настоящее время, поэтому я написал один (с помощью моих коллег). Не полный — достаточно, чтобы исследовать концепцию. Используя nikic PHP-Parser (https://github.com/nikic/PHP-Parser), можно найти все вызовы методов в методах класса, а затем mocks может быть создан для них.

По крайней мере, я, возможно, в конечном итоге доберусь до такой степени, что смогу использовать его для выполнения отдельных тестовых тестов.

Вряд ли возможно.

Современные методы автоматической генерации тестов зависят от наличия спецификаций для поведения кода, а не только для реализации. Вывод спецификации из PHP-кода не всегда легко для человека, не говоря уже о машине, поэтому я серьезно сомневаюсь, что можно было бы сделать эту работу для любого реального кода.

Автоматизированное тестирование с PHP

Я разработчик .net, так что извините за то, что я ничего не знаю о PHP . Я читал некоторые вещи в сети, но я не могу сказать, как это сравнивается с Asp.net MVC с точки зрения автоматического тестирования.

Я склонен думать, что PHP очень похож на классический ASP, за исключением того, что это ООП (не так ли?). Чтобы улучшить его тестируемость, вы должны следовать определенным шаблонам разработки и стилю кода, чтобы обеспечить SoC (аналогично Asp.net WebForm, где вы, например, должны выполнять MVP, но вы все еще на расстоянии световых лет от того, что Asp.net MVC дает вам). из коробки).

Так. Как PHP сравнивается с Asp.net MVC с точки зрения написания автоматических тестов (особенно, конечно, модульных тестов)? Должен ли я использовать определенные библиотеки? Должен ли я следовать определенным правилам / шаблонам, чтобы это работало?

Как насчет непрерывной интеграции? Может ли тест там быть запущен автоматически?

3 ответа

В зависимости от ситуации я использую три: SimpleTest, PHPUnit и Zend_Test (на самом деле это просто оболочка для PHPUnit для использования с Zend Framework). Из них SimpleTest действительно проще. Тем не менее, PHPUnit обеспечивает большую мощность и гибкость.

Я не разработчик .net, поэтому я не могу сравнить их, но я могу помочь заполнить несколько пробелов в PHP.

Во-первых, хотя PHP поддерживает классы и ООП, как вы привыкли, в этом нет необходимости. На самом деле, некоторые проекты на основе PHP (такие как Drupal) практически не содержат ОО-кода.

Что касается тестирования PHP-кода, вы, вероятно, захотите использовать PHPUnit. Он реализует систему xUnit для тестирования кода на PHP. Но если PHPUnit вам не нравится, то вы можете попробовать SimpleTest, немного другую среду тестирования PHP.

php не сравнивается с asp.net mvc, так как php — это язык, подобный c # У них обоих есть OO, и вы можете тестировать методы и классы, как вы делаете в asp.net

Так же, как в asp.net у вас есть mvc в php тоже. Возможно, вы захотите взглянуть на некоторые фреймворки, такие как Symfony, которые работают на той же модели mvc.

Тестирование в .net выполняется с помощью NUnit или других, в PHP у вас есть несколько симуляторов, таких как PHPUnit, а в Symfony также есть Lime.

на самом деле, я нахожусь в oposit ситуации, пришедшей из php, а сейчас в разработке на c #, и все это почти то же самое .

тесты могут быть запущены автоматически, в .net вы, возможно, знаете nant (инструмент автоматического тестирования и сборки), ant — то же самое для php / java и hudson как инструмент для получения обзора всех сборок.

как реализовать автоматические функциональные тесты в php

Всюду я читал о важности автоматических тестов. Я понимаю важность, и сейчас я буду делать это в своих будущих проектах (немного поздно знаю, но лучше поздно, чем никогда ;-))

Я много читал об модульных тестах, и я знаю инструменты, которые я могу использовать (PHPUnit является предпочтительным инструментом почти всех). Но как насчет функциональных тестов? Я прочитал некоторую специальную литературу о функциональных тестах, но я не смог найти подробное описание того, как реализовать такие тесты и какие инструменты я могу использовать. Какая разница?

Я потратил некоторое время на рекламу, поэтому я был бы рад, если бы кто-нибудь мог дать мне ссылку на документацию или рекомендацию для книги этой темы.

Каждый намек очень ценится 😉

php testing phpunit

2 ответа

Это зависит от того, что вы хотите протестировать и кто пишет этот тест. Если деловые люди хотят написать некоторые функциональные тесты, у вас должен быть подход ATDD с такими инструментами, как Behat и Selenium.

Если вы (разработчик, я думаю), хотите написать функциональные тесты, что вы хотите проверить? Вы хотите проверить такие вещи, как

Для первого подхода вы должны снова использовать инструмент, такой как Selenium, который может имитировать все действия пользователей. Это очень мощный и популярный инструмент. Я думаю (но это всего лишь мнение), что этот подход имеет слишком большую детализацию с пользовательским интерфейсом, и он просто хорош для тестов без регрессии, а не для TDD.

Мой подход заключается в том, чтобы писать тесты высокого уровня с помощью PHPUnit. Эти тесты напрямую направляют ваши маршруты или контроллеры и проверяют соблюдение всех бизнес-правил. С помощью этих тестов я могу проанализировать DOM, чтобы проверить, есть ли хорошая информация на странице (например, с помощью искателя symfony). Эти тесты быстро записываются и интегрируются в рабочий процесс PHPUnit, поэтому его легко начать. Я не знаю, можем ли мы назвать это «функциональные тесты», но они выполняют эту роль в моих проектах.

Но писать такие тесты зависит от многих ваших фреймворков. Я использую Laravel 4, который предназначен для проверки, поэтому он действительно прост, но в предыдущем опыте (с FuelPHP) это было невозможно.

Надеюсь, это поможет вам поднять собственное мнение.

Функциональные тесты основаны на сценариях использования. Существует два подхода к этому:

  1. Вы начинаете с документа прецедентов и определяете целевые устройства. то для каждого случая/устройства вы пишете скрипт с тем, что адаптировано к вашей среде (для Интернета, Selenium — очень хороший выбор)
  2. Когда у вас есть существующий сайт или продукт: вы фиксируете свой трафик и воспроизводите реальные последовательности использования, которые будут проверять не регрессию (с функциональной точки зрения). Это немного сложно, но очень мощно.

Обратите внимание, что оба подхода не являются несовместимыми, а дополняют друг друга.

Что вы хотите проверить и с чего вы начинаете?

Написание автоматических тестов и среда phpUnit PHP

Продолжение статьи о модульных тестах в PHP. В этой части рассмотрим поставщики данных, фикстуры, подмену зависимостей, тесты с виртуальной файловой системой, тесты исключений и взаимодействия с базой данных.

Содержание

Статья получилась огромная, потому разделена на 3 части. Для удобства содержание продублированно в каждой части, переходы на текущей странице выделены жирным шрифтом.

Поставщики данных (data providers)

Возьмем пример сложнее (см. полную версию в [src/Strings.php] в архиве с исходниками). Приведенный ниже метод возвращает фразу в правильном склонении в зависимости от числа, идущего с текстом:

Тестовый метод (см. [tests/unit/StringsTest.php] ):

Data prov >@dataProvider . Требования в методу-поставщику: он должен возвращать двумерный массив значений. Каждый подмассив — это набор данных на один тест-случай. Подмассив должен содержать элементы в том же количестве и порядке, как как это требуется в параметрах тест-метода.

PHPUnit не требует использовать ассоциативные массивы, но для удобства чтения можно задавать ключи любому из них.

Если в вашем поставщике данных возникнет исключение, тогда PhpUnit закончит тестирование с сообщением «No tests executed!», что вообще ни о чем не говорит. Включайте отладчик и ищите, что у вас не так в DataProvider .

Альтернатива использования поставщика данных — написать отдельные тест-методы на каждый случай. Или запилить все в один тест-метод, хотя я рекомендую избегать такого решения в больших тестах.


Прим.: в том же тестовом классе есть пример, как бы выглядел тест без использования DataProvider.

Еще один пример организации DataProv >[tests/dummy_examples/ProductValidatorTest.php] , метод test_checkAttrValueWithType() .

Важно: во время выполнения теста сначала вызывается поставщик данных, потом setUpBeforeClass() и setUp() (о них в следующем разделе). Т.е. в dataProvider() нельзя полагаться на данные, которые могут быть заданы в setUpBeforeClass() | setup() тестового метода.

Фикстуры

Одной и наиболее времязатратных частей написания тестов является установка «мира» приложения в известное состоянии и откат к этому состоянию после теста. Это известное состояние называется фикстурой теста. (перевод из мануала PHPUnit).

PHPUnit позволяет организовывать тестовое окружение в отдельно взятом классе, а так же для каждого выполняемого теста в классе. Для этого есть группа методов, о которых подробно расписано в мануале PHPUnit: 4. Fixtures. Кратко расскажу.

Приведенные ниже методы (если они вам нужны для тестов) нужно реализовывать прямо в ваших тестовых классах:

  • сначала вызов всех методов поставщиков данных
  • setUpBeforeClass() статичный метод, выполняется на этапе создания тест-класса. Аналогичный ему статический метод tearDownAfterClass() выполняется после всех тестов
  • Динамический метод setUp() выполняется перед каждым тестом, tearDown() после каждого теста
  • Динамический метод assertPreConditions() выполняется перед первым утверждением в каждом тесте. assertPostConditions() выполняется, если тест успешно завершился.

Прим: найдите в мануале пример Example 4.2 и результат его выполнения. Этот пример показывает последовательность вызова всех методов фреймворка для установки фикстур.

Как использовать эти методы — решать вам. Идея простая: все, что можно инициализировать для всех/каждого тест-метода — выносят в методы setUpBeforeClass() и setUp() соответственно. Если после теста требуется уборка (например, очистка кеша), вызываются соответствующие методы отката.

Примеры использования в архиве исходников можно посмотреть в [tests/unit/FSTest.php] и [tests/dummy_examples/ProductValidatorTest.php] . Содержимое этих методов может быть пока непонятно, но можно уловить мысль, что в них писать. Коротко: что-угодно общее для всех тест-методов.

Еще такой интересный момент: в unit-тестах можно принебречь оптимизацией или производительностью в пользу контролируемого поведения. Поэтому часто, вместо однократной инициализации окружения для всего класса через метод setUpBeforeClass() используют setUp() для создания известной среды для каждого тест-метода.

Подмена зависимостей

Подмена средствами PHPUnit

Тут мне трудно было выбрать, что рассказывать в статье, а за чем отправить в мануал PHPUnit: 9. Test Doubles. Там всего одна страница, и на примерах изложено вполне доступно. Я не хочу переписывать эту часть из документациии. Но все же скажу пару слов.

Как делается подмена зависимостей в PHPUnit 6.1. Напомню пример из теории (прим.: там класс назывался SomeClass ):

Тест с подменой зависимостей:

Как видно из кода выше, для подделки использовали разные методы. Дело в том, что метод createMock() — это обертка. На самом деле, в нем выполняется цепочка методов PHPUnit:

Все приведенные методы — публичные, поэтому при необходимости можно создать «тюнингованный» объект подделки. Так же можно вклиниться в эту цепочку, добавив вызовы других методов движка.

Подделки могут возвращать не только скалярные значения. У PHPUnit есть методы на все возможные случаи подмены.

Еще один пример подделки зависимости [tests/dummy_examples/ProductValidatorTest.php] , метод test_validateAttributes() , блок кода Act.

В тест-методах можно строить утверждения относительно подмененного объекта (понятие mock помните?). И вот тут еще большее поле для деятельности. У меня нет простого, но сколь-нибудь полезного примера, поэтому лучше смотрите примеры в мануале PHPUnit. Mock Objects, если у вас возникнет такая необходимость. Как было отмечено в теоретической части статьи, проверка взаимодействий — это самый крайний случай в модульном тестировании, когда иначе никак проверить метод не получается.

PHPUnit позволяет проверить, что подменяемый метод вызван ожидаемое количество раз, с определенными аргументами или их последовательностью (если вызовов несколько). Так же можно описать условия, при которых ожидаются определенные аргументы. Я сильно в эту тему не вдавался, обычно хватает тестирования в первых двух направлениях (результат или состояние).

Подмена с использованием Mockery

Mockery это PHP-фреймворк, запиленный специально для подмены объектов в unit-тестах. Он разработан, как альтернатива библиотеке подмены в PHPUnit, может использоваться в нем или как отдельный модуль, т.е. его можно подключить в другие тестовые движки. Основная фича — использование человекопонятного предметно-ориентированного языка (Domain-specific language, DSL).

Простым примером предметно-ориентированного языка является SQL для СУБД.

Приведенный выше тест (см. Подмена средствами PHPUnit) станет таким:

По ему мнению, в текущей версии PHPUnit удобная библиотека по созданию фейков и с этим фреймворком не требуется сторонний модуль подмены.

AspectMock

AspectMock проксирует все вызовы всех методов и позволяет их налету подменить. Я попробовал — это действительно круто. Но в итоге с моим движком он работать не смог, конфликтнул где-то. Т.о. возьмите на вооружение, если сможете подружить его с вашим проектом.

Мастер Йода рекомендует:  Я ужасный программист. Что мне с этим делать

Настройка. В bootstrap.php тестов прописываем типа этого (в исходниках см. [tests/bootstrap.php] ):

Пример все того же теста, но теперь с подменой через AspectMock:

«Killer feature» AspectMock именно в возможности подменить вообще любой класс или метод, независимо от того, был ли он как-либо внедрен или явно вызывается прямо в функции. Может оказаться полезно, если код изначально не был создан с оглядкой на тесты и представляет собой залипуху и кучки байт.

Тестирование с виртуальной файловой системой

Проблема: есть метод, взаимодействующий с реальной файловой системой. Нужно протестировать именно само взаимодействие, но при этом подменить ФС на виртуальную.

Ставим vfsStream и пользуемся 🙂

Эта библиотека эмулирует любые операции с файловой системой: CRUD файлов и каталогов, права доступа и т.д. Подробное использование расписано в мануале. Простой пример использования:

Более расширенный пример с кучей вариантов использования виртуальной ФС см. в архиве исходников [/tests/unit/FSTest.php]

  • vfsStream вообще не любит слеши. Например, создание каталога с концевым слешем или без него — это два разных набора в vfsStream::getChildren() . За их использованием нужно внимательно следить во избежание проблем в тестовых утверждениях.
  • с виртуальной ФС не работает функция PHP glob() . Описание проблемы и вариант решения тут. Коротко: нужно придумать свою функцию, выполняющую ту же работу, что и glob() и использовать ее во всех местах, где возможно обращение к виртуальной ФС. Мое решение основано на PHP::DirectoryIterator , его можно увидеть в FS::dirList() .

Тестирование исключений

В PHPUnit метод expectException() , а так же директива @expectedException используются в тестах для указания ядру фреймворка «ожидать такое-то исключение». В итоге тест считается пройденным если исключение возникло.

И тут есть ньюансик: после того, как PHPUnit поймает ожидаемое исключение, выполнение тест-метода прекратится! Т.е. expectException() — это аналог assert-метода, только с прерыванием. Есть так же методы на проверку кода и сообщения исключения.

Почему это важно: нельзя в одном тест-методе проверить нормальное поведение и проброс исключения. Т.е. какая-то из ситуаций не выполнится, тест будет провален.

  1. забить на проверку исключений в принципе;
  2. писать тест-методы на нормальное поведение и на каждое пробрасываемое исключение отдельно;
  3. в тест-методе оформлять блоки try. catch ;
  4. использовать data provider.

Последний вариант мне представляется наиболее предпочтительным. Причем data provider позволяет описать вообще все тест-кейсы в одном методе.

См. скрипт архива исходников [tests/dummy_examples/ExceptionsTest.php] . Пример ExceptionsTest::test_normalizePriority() демонстрирует решение с data prov >test_getTargetFileName() для демонстрации исключения в одном методе вместе с нормальными ситуациями.

Пример отдельного теста только на проброс исключения см. в [unit_simple/tests/FSTest.php] метод test_fuse_removeDir() . Исключение ожидается всего одно, data provider там не нужен. Но чтобы создать исключительную ситуацию в этом методе, требуется большая подготовка, поэтому тест-метод оформлен отдельно.

Тестирование запросов в базу данных

Тестирование взаимодействия с БД — это скорее интеграционный тест, но все же стоит один раз напрячься и сделать. Это несложно. Хотя зависит от проекта, я не настаиваю 🙂


В мануле много всего расписано по этому вопросу, но я особо не занимался тестированием именно взаимодействия с БД. На практике написал несколько простых тестов с маленькой базой.

В общих чертах: вам нужна будет еще одна база данных помимо боевой, структура должна соответствовать рабочей БД. Если используете миграции, поддержка актуальной структуры — не проблема. В PHPUnit нужно добавить модуль:

Далее см. в архиве исходников [tests/dummy_examples/DBEmptyTest.php] .

В тестовый класс нужно подключить трейт TestCaseTrait (до версии PHPUnit 6.1 был суперкласс для наследования, теперь трейт) и реализовать два абстрактных метода: подключение к базе и загрузка данных (фикстур) в таблицы.

Прим: реализация подключения к базе зависит от конкретного приложения. Методы getConnection() и getDataSet() выполняются перед каждым тест-методом.

Как это работает: PHPUnit подключается к базе, очищает таблицы и грузит в них данные, которые вы укажете. Ваш проверяемый класс должен уметь подключаться к тестовой БД. Далее обычная процедура тестирования — Arrange Act Assert. В конце — откат через tearDown() , если требуется.

PHPUnit предоставляет кучу форматов для загрузки данных: несколько XML форматов, YAML, CSV, arrays и какие-то велосипеды. Имхо, удобнее всего YAML.

См. в архиве исходников пример подготовленных данных — [tests/dummy_examples/fixtures/*.yml] , тест в [tests/dummy_examples/LabelModelTest.php]

По моему мнению, этот модуль в PHPUnit еще сырой: слишком много возможностей, документация раскрывает не все, что есть. Видимо автор еще не определился.

Модульное тестирование в PHP средствами PHPUnit

Всем доброго времени суток! Сегодня я хотел бы поговорить с Вами о том, что такое модульное тестирование в PHP.

При написании даже самых простых программ периодически приходиться останавливаться и проводить рефакторинг для того, чтобы понять правильно ли написана программа. А рефакторинге кода в PHP я уже рассказывал в одной из публикаций на сайте, с которой можно ознакомиться здесь.

В общем, конечно, данный подход неплох, однако у него есть существенные недостатки. Так, например, при написании, какого-либо достаточно крупного проекта, код будет постепенно засоряться закомментированными отладочными функциями, типа print или print_r.В случае работы над собственным проектом, код которого никто, ну или почти никто, читать не собирается, он, до некоторой поры, будет оправдан.

Однако давайте представим такую ситуацию: Вы пишете сайты для заказчиков на собственной системе управления контентом. Заказчики довольны, Вы чувствуете себя прекрасно, но в один день понимаете, что система, которую Вы разработали, уже не отвечает предъявляемым к ней требованиям, она нуждается в изменениях. И Вы начинаете переписывать одну часть системы за другой.

Наступает такой момент, когда один новый класс, метод, условие или цикл — рушат всю систему. Изменения в одном месте приводят к ошибкам в другом. И вот они уже лезут без конца, как из рога изобилия, и становиться понятно, что так дальше невозможно. А все было бы гораздо лучше, если бы сначала, помимо всего прочего, были бы написаны PHP Unit тесты. Не зря ведь говорит, Мартин Фаулер, что когда бы Вы ни пытались напечатать что-то через print в целях отладки или рефакторинга, лучше напишите это в виде Unit теста.

Итак, с теорией вроде ознакомились, теперь перейдем непосредственно к коду. Здесь необходимо сделать важные замечания, все операции проводятся на ПК под управлением Windows 7 c установленным PHP 7 версии. Дальше будет по пунктам.

1) Скачиваем по ссылке файл phpunit-6.3.0.phar, который представляет собой исполняемый PHP архив.

2) Загруженный файл перемещаем в папкуC:\bin. В этой же папке создаем файл phpunit.bat, записываем в него следующее содержимое: @php C:\bin\phpunit-6.3.0.phar %*

Учтите, что путь C:\bin должен быть определен в системной переменной PATH, иначе при попытке выполнить в консоли команду phpunit Вы получите ошибку!

3) Откройте консоль и выполните команду phpunit, и если все правильно, то в консоли должна отобразиться справка.

Конечно, существуют и другие способы установки PHPUnit, однако я нашел данный способ наиболее приемлемым. За дополнительной информацией Вы всегда можете обратиться на официальный сайт проекта PHPUnit. Итак, установка завершена, теперь перейдем непосредственно, к коду.

array_push($stack, ‘foo’); // добавили одним элемент в массив
$this->assertEquals(‘foo’, $stack[count($stack)-1]); // проверили на равенство
$this->assertEquals(1, count($stack));

$this->assertEquals(‘foo’, array_pop($stack));
$this->assertEquals(0, count($stack));
>
>
?>

Код хорошо комментирован, однако поясню пару моментов. Краеугольным камнем Unit тестирования является утверждение (assertion). Утверждение — это Ваше предположение об ожидаемом значении, или другими словами Вы утверждаете, что значение переменной, элемента массива, результат выполнения метода и т.д. будет равно такому-то значению. В примере выше, при первоначальном создании массива, ожидаемое значение его длины — 0. Так оно и есть на самом деле в нашем примере.

В данном случае мы используем только одно утверждение assertEquals, хотя в классе TestCase библиотеки PHPUnit их несколько десятков, на все случаи жизни, так сказать.

Так тест мы написали, а что дальше? А дальше его надо запустить. Для этого открываем консоль, переходим в папку с нашим тестом (PHP Unit тесты обычно располагаются в отдельной папке tests) и запускаем команду phpunit, передав ей в аргументе текущий каталог (обозначается одной точкой).

cd C:/Projects/php/tests && phpunit .

Данная команда автоматически пройдется по всем PHP тестам, которые есть в данном каталоге. По завершении выполнения, она выведет информацию о том, сколько тестов пройдено и, возможно, провалено.

Таким образом, сегодня мы с Вами выяснили что такое Unit тестирование в PHP, что применять его не только полезно, но и нужно. А если Вы знаете PHP плохо, или не знаете его совсем, то специально для Вас у меня есть отличный видеокурс «PHP и MySQL с Нуля до Гуру 2.0», в котором, я, в частности, подробно разбираю тему модульного (Unit) тестирования в PHP.

Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

Она выглядит вот так:

  • BB-код ссылки для форумов (например, можете поставить её в подписи):
  • Комментарии ( 2 ):

    А нет статьи где описывается как сделать регистрацию\вход\управление пользователями и т.д. всё вместе

    Здравствуйте! На сайте есть статьи по указанным Вами темам, их можно найти через форму поиска. Однако, если Вы хотите получить отличные знания по этим темам, то можете посмотреть курс, в котором эти темы разбираются очень подробно. Вот ссылка: https://srs.myrusakov.ru/php2?utm_source=MyRusakov.ru&utm_campaign=php2&utm_content=article_1017

    Для добавления комментариев надо войти в систему.
    Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.

    Copyright © 2010-2020 Русаков Михаил Юрьевич. Все права защищены.

    PHPUnit. Теория написания тестов

    Допустим, есть класс. С двумя методами.

    Теперь вопрос. При покрытии тестами, что я должен передавать методам? То, что они ожидают принять в идеале? То есть, валидную строку в первом случае и непустое свойство во втором.

    Или то, что они не ожидают? Всякую невалидную чушь в первом случае и отсутствие свойства во втором.

    Или два теста, один на ожидаемые параметры, а второй на неожиданные?

    P.S. Только разбираюсь с тестированием, так что в матчасти не силен.

    P.P.S. Если это важно, то в случае успеха методы выдают true , а в случае неудачи — выбрасывают Exception . Поскольку, при неправильных параметрах продолжать выполнение скрипта не имеет смысла.


    1 ответ 1

    Тесты должны покрывать функциональность модуля в различных типичных сценариях, и позитивных, и негативных. Методы класса должны возвращать ожидаемые значения, или ожидаемым образом реагировать при передаче неправильных типов на вход, например, выбрасывать ожидаемые исключения. Вы привели довольно простой пример, там можно придумать не так и много сценариев для тестирования. Но в более сложных ситуациях, вы должны предусмотреть и менее очевидные варианы. К примеру, передачу в метод аргумента правильного типа, но не верно сконфигурированного. Тесты должны покрывать большинство ветвлений исполнения программы, чем важнее модуль, тем более полным должно быть покрытие. Также стоит покрывать тестами типичные сценарии взаимодействия с другими модулями системы. Такие IDE как PhpStorm отлично помогают ориентироваться в том, какие места кода не покрыты тестами. Позже, с каждым обнаруженным и исправленным багом, дописывайте тест, который будет отлавливать такие ошибки. Плюс при написании тестов отлично всплывают все зависимости модулей друг от друга, так что тесты скорее всего полтолкнуи васк рефакторингу отдельных модулей и помогут более правильно проектировать свои классы. Плохо спроектированные классы почти всегда трудно покрыть нормальными тестами, не протащив с собой в тесты простыню из лишних зависимостей.

    UPD. Пример для вашего класса

    Опять же, учитывая, что пример простой, то и тесты не особо интересные.

    8 незаменимых инструментов для тестирования PHP

    Для получения качественного кода, мы должны выполнять тестирование во время его написания (если не использовать TDD). Однако, трудно сделать выбор среди такого широкого круга PHP инструментов тестирования.

    Эта статья посвящена самым широко распространенным инструментам тестирования. В ней собрана обновленная информация по состоянию QA инструментов в 2020 году.

    PHPUnit

    PHPUnit — это фреймворк PHP для тестирования. Он был разработан Себастьяном Бергманом (Sebastian Bergmann) в 2004 и является одним из многих доступных средств тестирования моделей РНР в процессе разработки. Сейчас доступна 6 версия фреймворка, требующая PHP 7.

    Cucumber

    Cucumber — это фреймворк для создания тестирования по спецификациям. Он известен своими описательными сгенерированными текстами, которые очень удобно и просто читать. Официальной реализацией PHP для Cucumber является Behat.

    Ниже приведен пример из документации, который хорошо отображает выразительность фреймворка.

    Atoum

    Atoum – еще один фреймворк для тестирования PHP. Это автономный пакет, который можно установить через GitHub, Composer или исполняемый файл PHAR.

    Тесты Atoum очень читабельны, имеют выраженные имена методов и взаимосвязи.

    Selenium

    Selenium — это инструмент для автоматического браузерного тестирования (интегрированное и приемочное тестирование). Он преобразует тесты в команды API браузера и утверждает ожидаемые результаты. Selenium поддерживает большинство доступных браузеров.

    Мы можем использовать Selenium с PHPUnit, используя расширение.

    Вот простой пример:

    Dusk

    Dusk из Laravel – еще один инструмент автоматизации браузера. Он может использоваться автономно (с chromedriver) или с Selenium. Он имеет простой в использовании API и охватывает все возможности тестирования, такие как ожидание элементов, загрузка файлов, управление мышью и т.д. Вот простой пример:

    Kahlan

    Kahlan – это полнофункциональная среда тестирования Unit & BDD, которая использует описательный синтаксис.

    Из приведенного выше синтаксиса видно, что он похож на тесты Behat. Kahlan поддерживает Stub-инг и Mock-инг (stubbing and mocking out of the box) без зависимостей, покрытия кода, отчетности и т.д.

    php_testability

    Последний пакет, о котором мы упомянем здесь – PHP Testability. Это инструмент статического анализа, который рассказывает о проблемах с тестируемостью в вашей программе и генерирует подробный отчет.

    Пакет в настоящее время не имеет помеченного релиза, на который можно полагаться, но вы можете безопасно использовать его в разработке. Вы можете установить его через Composer:

    Мастер Йода рекомендует:  Разместить рекламу в Facebook стало проще и удобнее

    Затем запустить его следующим образом:

    Сервисы непрерывной интеграции (CI)

    Важная часть в предоставлении кода при работе с командами – это возможность автоматически проверять код до его объединения с официальным репозиторием проекта. Большинство доступных сервисов/инструментов CI предоставляют возможность тестировать код на разных платформах и конфигурациях, чтобы убедиться, что ваш код безопасен для слияния.

    Существует множество сервисов, которые предлагают доступные цены, но вы также можете использовать инструменты с открытым исходным кодом:

    • PHPCI: (с открытым исходным кодом)

    • TravisCI: (бесплатно для проектов с открытым исходным кодом)

    • SemaphoreCI: (бесплатно для проектов с открытым исходным кодом)

    Заключение

    Принять культуру тестирования кода сложно, но она понемногу развивается с практикой. Если вы заботитесь о своем коде, вы должны его протестировать! Перечисленные в этой статье инструменты и ресурсы помогут вам разобраться и начать работу.

    Глава 4. Написание тестов на PHPUnit

    Пример 4.1, «Тестирование операций с массивами с использованием PHPUnit» показывает как можно писать тесты на PHPUnit для операций с массивами в PHP. Этот пример представляет базовые соглашения и шаги для написания тестов с помощью PHPUnit:

    Тесты для класса Class содержатся в классе ClassTest .

    ClassTest унаследован (чаще всего) от PHPUnit_Framework_TestCase .

    Тесты это публичные методы с именами test* .

    Кроме этого, можно использовать аннотацию @test в док-блоке чтобы пометить метод как тест.

    Внутри тестовых методов для проверки того что реальные данные соответствуют ожидаемым используются методы-утверждения (assertion methods) такие как assertEquals() (см.«Утверждения (Assertions)»)

    Пример 4.1. Тестирование операций с массивами с использованием PHPUnit

    Всякий раз, когда вы испытываете искушение напечатать что-то внутри оператора print или отладочного выражения, напишите это как тест.

    — Мартин Фаулер

    Межтестовые зависимости

    Модульные тесты главным образом в виде практики которая помогает разработчикам идентифицировать и исправить баги, реорганизовывать (refactor) код и служит в качестве документации для модуля тестируемой программы. Для того чтобы достичь этих преимуществ, модульные тесты, в идеале, должны охватывать все возможные пути исполнения программы. Один модульный тест обычно покрывает один конкретный путь в одной функции или методе. Однако тестовый метод это не обязательно инкапсулированная, независимая сущность. Часто существуют неявные зависимости между тестовыми методами, скрытые в сценарии реализации теста.

    — Adrian Kuhn et. al.

    PHPUnit поддерживает опсание явных зависимостей между тестовыми методами. Эти зависимости не определяют порядок в котором тесты будут выполняться, но они позволяют передавать тестовые данные (фикстуры), созданные поставщиком, (producer) потребителям (consumers), котрые от него зависят.

    Поставщик — это тестовый метод, который предоставляет свой тестируемый модуль в качестве возвращаемого значения.

    Потребитель — это тестовый метод, который зависит от одного или более поставщиков и их возвращаемых значений.


    Пример 4.2, «Использвание аннотации @depends для описания зависимостей » показывает как использовать аннотацию @depends для описания зависимостей между тестовыми методами.

    Пример 4.2. Использвание аннотации @depends для описания зависимостей

    В приведённом выше примере первый тест, testEmpty() , создаёт новый массив и утверждает что массив пустой. Затем тест возвращает фикстуру в виде результата. Второй тест, testPush() , зависит от testEmpty() и получает результат от теста-зависисмости в качестве аргумента. Наконец, testPop() зависит от testPush() .

    Для того чтобы находить дефекты быстро, нам нужно сконцентрировать внимание на соответствующих тестах. Для этого PHPUnit пропускает исполн ение тестов, когда зависимость провалилась. Это улучшает локализацию дефектов за счёт использования зависимостей между тестами как показано в Пример 4.3, «Использование зависимостей между тестами».

    Пример 4.3. Использование зависимостей между тестами

    У теста может быть несколько аннотаций @depends . PHPUnit не изменяет порядок в котром будут выполняться тесты, поэтому вы должны убедиться что все зависимости теста удовлетворены до его выполнения.

    Провайдеры данных

    Тестовый метод может принимать произвольные аргументы. Эти аргументы должны быть предоставлены методом — провайдером данных ( provider() в Пример 4.4, «Использование провайдера данных, который возвращает массив массивов »). Метод, который будет использован в качестве провайдера данных, обозначается с помощью аннотации @dataProvider .

    Метод провайдера данных должен быть public и возвращать либо массив массивов либо объект реализующий интерфейс Iterator , который возвращает массив при каждой итера ции. Для каждого массива являющегося частью коллекции будет вызван тестовый метод с элементами массива в качестве параметров

    Пример 4.4. Использование провайдера данных, который возвращает массив массивов

    Пример 4.5. Использование провайдера данных, который возвращает объект-итератор

    Пример 4.6. Класс CsvFileIterator

    Примечание

    Если тест получает данные как от @dataProvider так и от теста (или тестов) от которых он зависит ( @depends ), аргументы от провайдера будут переданы в тест первыми, а аргументы от @depends добавлены в конец списка аргументов.

    Примечание

    Если один тест зависит от другого теста, который использует провайдер, тест-потребитель выполнится если тест-поставщик упешно пройдёт хотя бы для одного набора параметров из провайдера. Результат выполнения теста-поставщика, который использует провайдера, не может быть передан тесту-потребителю.

    Примечание

    Все функции-провайдеры выполняются до того как впервые будет вызван метод setUp . Поэтому, вы не сможете получить доступ к переменным которые вы определили в нём изнутри провайдера.

    Тестирование исключений

    Пример 4.7, «Использование аннотации @expectedException» показывает как c помощью аннотации @expectedException проверить было ли вызвано исключение в тестируемом коде.

    Пример 4.7. Использование аннотации @expectedException

    Дополнительно вы можете использовать @expectedExceptionMessage и @expectedExceptionCode в сочетании с @expectedException для проверки сообщений и кодов исключений как показано в Пример 4.8, « Использование аннотаций @expectedExceptionMessage и @expectedExceptionCode ».

    Пример 4.8. Использование аннотаций @expectedExceptionMessage и @expectedExceptionCode

    « @expectedExceptionMessage » и « @expectedExceptionCode » приводят другие примеры использования @expectedExceptionMessage и @expectedExceptionCode соответственно.

    В качестве альтернативы, можно использовать метод setExpectedException() , чтобы задать ожидаемое исключение Пример 4.9, «Ожидаем исключение которое будет вызвано тестовым кодом».

    Пример 4.9. Ожидаем исключение которое будет вызвано тестовым кодом

    Таблица 4.1. Методы тестирования исключений

    Метод Назначение
    vo , integer $exceptionCode = NULL]) Устанавливает тип ( $exceptionName ) ,сообщение ( $exceptionMessage ), и код ( $exceptionCode. ) ожидаемого исключения.
    String getExpectedException() Возвращает тип ожидаемого исключения.

    Также для тестирования исключения вы можете использовать подход который иллюстрирует пример Пример 4.10, «Альтернативный подход к тестированию исключений»

    Пример 4.10. Альтернативный подход к тестированию исключений

    Пример 4.10, «Альтернативный подход к тестированию исключений» демонстрирует, что если код от которого мы ожидали вызов исключения не вызовет его, последующий вызов метода fail() прервёт тест и сообщит о проблеме в тесте. Если ожидаемое исключение было вызвано, блок catch будет выполнен и тест завершится успешно.

    Тестирование ошибок PHP

    По умолчанию, PHPUnit преобразует ошибки, предупреждения и замечания (PHP Error, PHP Warning, PHP Notice соответственно), которые возникают во время выполнения теста в исключения. Используя эти исключения вы можете, например, что тест вызовет ошибку PHP, как это показывает Пример 4.11, «Ожидание ошибки PHP с использованием @expectedException».

    Пример 4.11. Ожидание ошибки PHP с использованием @expectedException

    PHPUnit_Framework_Error_Notice и PHPUnit_Framework_Error_Warning представляют замечания и предупреждения PHP соответственно.

    Примечание

    Вы должны быть как можно более конкретны когда теститруете исключения. Проверка слишком общих классов может приветси к нежелательным побочным эффектам. Поэтому проверка на встроенный класс Exception при помощи @expectedException или setExpectedException() больше не разрешена.

    Когда вы тестируете код, основаный на функциях, которые вызывают ошибки, например fopen иногда может оказаться полезным подавление ошибок во время тестирования. Это позволит вам проверять возвращаемые значения подавляя замечания, которые иначе привели бы phpunit к PHPUnit_Framework_Error_Notice .

    Пример 4.12. Testing return values of code that uses PHP Errors

    Без подавления ошибок мы бы получили fopen(/is-not-writeable/file): failed to open stream: No such file or directory .

    Тестирование вывода

    Иногда вам нужно проверить что выполнение метода, например, даёт нам ожидаемый вывод (через echo или print ) Класс PHPUnit_Framework_TestCase использует Буферизацию Вывода для того чтобы предоставить такую возможность.

    Пример 4.13, «Тестирование вывода функции или метода» демонстрирует как использовать метод expectOutputString() для того чтобы задать ожидаемый вывод. Если это вывод не будет сгенерирован тест отмечен как проваленый.

    Пример 4.13. Тестирование вывода функции или метода

    Таблица 4.2. Методы для тестирования вывода

    Метод Назначение
    void expectOutputRegex(string $regularExpression) Задаёт регулярное выражение $regularExpression которому должен соответствовать вывод
    void expectOutputString(string $expectedString) Устанавливает ожидаемое значение $expectedString которому должен быть равен вывод.
    bool setOutputCallback(callable $callback) Устанавливает callback-функцию которая может быть использована, например, для нормализации вывода

    Примечание

    Обратите внимание, что PHPUnit проглатывает весь вывод который генерируется во время выполнения теста. В строгом режиме (strict mode) тест, кторый генерирует вывод провалится

    Утверждения (Assertions)

    Эта секция перечисляет различные доступные методы-утверждения

    assertArrayHasKey()

    assertArrayHasKey(mixed $key, array $array[, string $message = »])


    Сообщает об ошибке $message если $array не содержит ключа $key .

    assertArrayNotHasKey() утверждает обратное и принимает тот же набор аргументов

    Пример 4.14. Использование assertArrayHasKey()

    assertClassHasAttribute()

    Сообщает об ошибке $message если $className::attributeName не существует.

    assertClassNotHasAttribute() утверждает обратное и принимает тот же набор аргументов.

    Пример 4.15. Использование assertClassHasAttribute()

    assertClassHasStaticAttribute()

    Сообщает об ошибке $message если статический аттрибут $className::attributeName не существет.

    assertClassNotHasStaticAttribute() утверждает обратное и принимает тот же набор аргументов.

    Пример 4.16. Использование assertClassHasStaticAttribute()

    assertContains()

    assertContains(mixed $needle, Iterator|array $haystack[, string $message = »])

    Сообщает об ошибке $message если $needle не является элементом $haystack .

    assertNotContains() утверждает обратное и принимает тот же набор аргументов.

    assertAttributeContains() и assertAttributeNotContains() это удобные обёртки, которые используют публичные , защищенные , или приватные аттрибуты класса или объекта в качестве области поиска.

    Пример 4.17. Использование assertContains()

    assertContains(string $needle, string $haystack[, string $message = »])

    Сообщает об ошибке $message если $needle не является подстрокой $haystack .

    Пример 4.18. Использование assertContains()

    assertContainsOnly()

    assertContainsOnly(string $type, Iterator|array $haystack[, boolean $isNativeType = NULL, string $message = »])

    Сообщает об ошибке $message если $haystack содержит элементы отличные по типу от $type .

    $isNativeType флаг который определяет является ли $type встроенным типом PHP или нет.

    assertNotContainsOnly() утверждает обратное и принимает тот же набор аргументов.

    assertAttributeContainsOnly() и assertAttributeNotContainsOnly() это удобные обёртки, которые используют публичные , защищенные , или приватные аттрибуты класса или объекта в качестве области поиска.

    Пример 4.19. Использование assertContainsOnly()

    assertContainsOnlyInstancesOf()

    Сообщает об ошибке $message если $haystack содержит что-то кроме экземпляров класса $classname .

    Пример 4.20. Использование assertContainsOnlyInstancesOf()

    assertCount()

    assertCount($expectedCount, $haystack[, string $message = »])

    Сообщает об ошибке $message если количество элементов в $haystack не равно $expectedCount .

    assertNotCount() утверждает обратное и принимает тот же набор аргументов.

    Пример 4.21. Использование assertCount()

    assertEmpty()

    assertEmpty(mixed $actual[, string $message = »])

    Сообщает об ошибке $message если $actual не пустое.

    assertNotEmpty() утверждает обратное и принимает тот же набор аргументов.

    assertAttributeEmpty() и assertAttributeNotEmpty() это удобные обёртки, которые используют публичные , защищенные , или приватные аттрибуты класса или объекта в качестве области поиска.

    Пример 4.22. Использование assertEmpty()

    assertEqualXMLStructure()

    assertEqualXMLStructure(DOMElement $expectedElement, DOMElement $actualElement[, boolean $checkAttributes = FALSE, string $message = »])

    Сообщает об ошибке $message если структура XML элемента DOM в $actualElement не совпадает с структурой XML элемента DOM в $expectedElement .

    Пример 4.23. Использование assertEqualXMLStructure()

    assertEquals()

    assertEquals(mixed $expected, mixed $actual[, string $message = »])

    Сообщает об ошибке $message если переменные $expected и $actual не равны между собой.

    assertNotEquals() утверждает обратное и принимает тот же набор аргументов.

    assertAttributeEquals() и assertAttributeNotEquals() это удобные обёртки, которые используют публичные , защищенные , или приватные аттрибуты класса или объекта в качестве области поиска.

    Пример 4.24. Использование assertEquals()


    Более специфические сравнения, которые используются для определённых типов аргументов $expected и $actual смотрите ниже.

    assertEquals(float $expected, float $actual[, string $message = », float $delta = 0])

    Сообщает об ошибке $message если два числ а с плавающей запятой $expected и $actual отличаются более чем на $delta друг от друга.

    Пример 4.25. Использование assertEquals() с числами с плавающей запятой floats

    assertEquals(DOMDocument $expected, DOMDocument $actual[, string $message = »])

    Сообщает об ошибке $message если некомментированная каноническая форма XML документов представленых двумя объектами DOMDocument $expected и $actual не совпадает.

    Пример 4.26. Использование assertEquals() с объектами DOMDocument

    assertEquals(object $expected, object $actual[, string $message = »])

    Сообщает об ошибке $message если два объекта $expected и $actual имеют неодинаковые аттрибуты.

    Пример 4.27. Использование assertEquals() с объектами

    assertEquals(array $expected, array $actual[, string $message = »])

    Сообщает об ошибке $message если два массива $expected и $actual не равны.

    Пример 4.28. Использование assertEquals() с массивами

    assertFalse()

    assertFalse(bool $condition[, string $message = »])

    Сообщает об ошибке $message если $condition равно TRUE .

    Пример 4.29. Использование assertFalse()

    assertFileEquals()

    assertFileEquals(string $expected, string $actual[, string $message = »])

    Сообщает об ошибке $message если файл $expected не равен по содержимому файлу $actual .

    assertFileNotEquals() утверждает обратное и принимает тот же набор аргументов.

    Пример 4.30. Использование assertFileEquals()

    assertFileExists()

    assertFileExists(string $filename[, string $message = »])

    Сообщает об ошибке $message если файл $filename не существует.

    assertFileNotExists() утверждает обратное и принимает тот же набор аргументов.

    Пример 4.31. Использование assertFileExists()

    assertGreaterThan()

    assertGreaterThan(mixed $expected, mixed $actual[, string $message = »])

    Сообщает об ошибке $message если значение $actual не больше чем $expected .

    assertAttributeGreaterThan() это удобные обёртки, которые используют публичные , защищенные , или приватные аттрибуты класса или объекта в качестве актуального значения.

    Пример 4.32. Использование assertGreaterThan()

    assertGreaterThanOrEqual()

    assertGreaterThanOrEqual(mixed $expected, mixed $actual[, string $message = »])

    Сообщает об ошибке $message если значение $actual меньше значения $expected .

    assertAttributeGreaterThanOrEqual() это удобные обёртки, которые используют публичные , защищенные , или приватные аттрибуты класса или объекта в качестве актуального значения.

    Пример 4.33. Использование assertGreaterThanOrEqual()

    assertInstanceOf()

    assertInstanceOf($expected, $actual[, $message = »])

    Сообщает об ошибке $message если $actual не является экземпляром $expected .

    assertNotInstanceOf() утверждает обратное и принимает тот же набор аргументов.

    assertAttributeInstanceOf() и assertAttributeNotInstanceOf() это удобные обёртки, которые можно использовать с публичными , защищенными , или приватными аттрибутом класса или объекта.

    Пример 4.34. Использование assertInstanceOf()

    assertInternalType()

    assertInternalType($expected, $actual[, $message = »])

    Сообщает об ошибке $message если $actual не является переменной типа $expected .

    assertNotInternalType() утверждает обратное и принимает тот же набор аргументов.

    assertAttributeInternalType() и assertAttributeNotInternalType() это удобные обёртки, которые можно использовать с публичным , защищенным , или приватным аттрибутом класса или объекта.

    Пример 4.35. Использование assertInternalType()

    assertJsonFileEqualsJsonFile()

    assertJsonFileEqualsJsonFile(mixed $expectedFile, mixed $actualFile[, string $message = »])

    Сообщает об ошибке $message если значение $actualFile совпадает с $expectedFile .


    Пример 4.36. Использование assertJsonFileEqualsJsonFile()

    assertJsonStringEqualsJsonFile()

    assertJsonStringEqualsJsonFile(mixed $expectedFile, mixed $actualJson[, string $message = »])

    Сообщает об ошибке $message если строка $actualJson не совпадает с содержимым $expectedFile .

    Пример 4.37. Использование assertJsonStringEqualsJsonFile()

    assertJsonStringEqualsJsonString()

    assertJsonStringEqualsJsonString(mixed $expectedJson, mixed $actualJson[, string $message = »])

    Сообщает об ошибке $message если десериализованая строка $actualJson не равна десериализованой строке $expectedJson .

    Пример 4.38. Использование assertJsonStringEqualsJsonString()

    assertLessThan()

    assertLessThan(mixed $expected, mixed $actual[, string $message = »])

    Сообщает об ошибке $message если значение $actual больше или равно значению $expected .

    assertAttributeLessThan() удобная обёртка, которая позволяет применять assertLessThan к public , protected , или private аттрибута класса или объекта.

    Пример 4.39. Использование assertLessThan()

    assertLessThanOrEqual()

    assertLessThanOrEqual(mixed $expected, mixed $actual[, string $message = »])

    Сообщает об ошибке $message если значение $actual строго больше чем $expected .

    assertAttributeLessThanOrEqual() удобная обёртка, которая позволяет применять assertLessThanOrEqual к public , protected , или private аттрибута класса или объекта.

    Пример 4.40. Использование assertLessThanOrEqual()

    assertNull()

    assertNull(mixed $variable[, string $message = »])

    Сообщает об ошибке $message если $variable не NULL .

    assertNotNull() утверждает обратное и принимает тот же набор аргументов.

    Пример 4.41. Использование assertNull()

    assertObjectHasAttribute()

    assertObjectHasAttribute(string $attributeName, object $object[, string $message = »])

    Сообщает об ошибке $message если $object->attributeName не существует.

    assertObjectNotHasAttribute() утверждает обратное и принимает тот же набор аргументов.

    Пример 4.42. Использование assertObjectHasAttribute()

    assertRegExp()

    assertRegExp(string $pattern, string $string[, string $message = »])

    Сообщает об ошибке $message если строка $string не соответствует регулярному выражению $pattern .

    assertNotRegExp() утверждает обратное и принимает тот же набор аргументов.

    Пример 4.43. Использование assertRegExp()

    assertStringMatchesFormat()

    assertStringMatchesFormat(string $format, string $string[, string $message = »])

    Сообщает об ошибке $message если строка $string не соответствует формату $format

    assertStringNotMatchesFormat() утверждает обратное и принимает тот же набор аргументов.

    Пример 4.44. Использование assertStringMatchesFormat()

    Строка формата может содержать следующие шаблоны:

    %e : Обозначает разделитель папок, например / для Linux.

    %s : Один или более любых символов (включая пробелы) кроме символа конца строки.

    %S : Любое количество (ноль или больше) любых символов (включая пробелы) кроме символа конца строки.

    %a : Один или более любых символов включая пробелы и символ конца строки.

    %A : Любое количество (ноль или больше) любых символов, включая пробелы и символ конца строки.

    %w : Любое количество (ноль или больше) пробельных символов.

    %i : Целое число со знаком, например +3142 , -3142 .

    %d : Целое число без знака, например 123456 .

    %x : Один или более One or more шестнадцатиричных символов. Т.е. символов 0-9 , a-f , A-F .

    %f : Число с плавающей запятой, например: 3.142 , -3.142 , 3.142E-10 , 3.142e+10 .

    %c : Один любой символ.

    assertStringMatchesFormatFile()


    assertStringMatchesFormatFile(string $formatFile, string $string[, string $message = »])

    Сообщает об ошибке $message если строка $string не удовлетворяет формату из $formatFile .

    assertStringNotMatchesFormatFile() утверждает обратное и принимает тот же набор аргументов.

    Пример 4.45. Использование assertStringMatchesFormatFile()

    assertSame()

    assertSame(mixed $expected, mixed $actual[, string $message = »])

    Сообщает об ошибке $message если две переменных $expected и $actual не совпадают одновременно по типу и значению.

    assertNotSame() утверждает обратное и принимает тот же набор аргументов.

    assertAttributeSame() и assertAttributeNotSame() удобные обёртки для сравнения public , protected , or private аттрибутов классов или объектов.

    Пример 4.46. Использование assertSame()

    assertSame(object $expected, object $actual[, string $message = »])

    Сообщает об ошибке $message если две переменные $expected и $actual не ссылаются на один и тот же объект.

    Пример 4.47. Использование assertSame() with objects

    assertSelectCount()

    assertSelectCount(array $selector, integer $count, mixed $actual[, string $message = », boolean $isHtml = TRUE])

    Сообщает об ошибке $message если CSS селектор $selector выбирает из DOMNode $actual отличное от $count количество элементов.

    $count может быть одного из перечисленных типов:

    • boolean : Проверяет простое наличие ( TRUE ) или отсутствие ( FALSE ) элементов соответствующих селектору.
    • integer : Проверяет количество элементов.
    • array : Проверяет что количество элементов находится в заданном диапазоне заданном ключами массива в виде , > , , и >= .

    Пример 4.48. Использование assertSelectCount()

    assertSelectEquals()

    assertSelectEquals(array $selector, string $content, integer $count, mixed $actual[, string $message = », boolean $isHtml = TRUE])

    Сообщает об ошибке $message если CSS селектор $selector выбирает из DOMNode $actual отличное от $count количество элементов со значением $content .

    $count может быть одного из перечисленных типов:

    • boolean : Проверяет простое наличие ( TRUE ) или отсутствие ( FALSE ) элементов соответствующих селектору.
    • integer : Проверяет количество элементов.
    • array : Проверяет что количество элементов находится в заданном диапазоне заданном ключами массива в виде , > , , и >= .

    Пример 4.49. Использование assertSelectEquals()

    assertSelectRegExp()

    assertSelectRegExp(array $selector, string $pattern, integer $count, mixed $actual[, string $message = », boolean $isHtml = TRUE])

    Сообщает об ошибке $message если CSS селектор $selector выбирает из DOMNode $actual отличное от $count количество элементов со значением которое соответствуе регулярному выражению $pattern .

    $count может быть одного из перечисленных типов:

    • boolean : Проверяет простое наличие ( TRUE ) или отсутствие ( FALSE ) элементов соответствующих селектору.
    • integer : Проверяет количество элементов.
    • array : Проверяет что количество элементов находится в заданном диапазоне заданном ключами массива в виде , > , , и >= .

    Пример 4.50. Использование assertSelectRegExp()

    assertStringEndsWith()

    assertStringEndsWith(string $suffix, string $string[, string $message = »])

    Сообщает об ошибке $message если строка $string не заканчивается строкой $suffix .

    assertStringEndsNotWith() утверждает обратное и принимает тот же набор аргументов.

    Пример 4.51. Использование assertStringEndsWith()

    assertStringEqualsFile()

    assertStringEqualsFile(string $expectedFile, string $actualString[, string $message = »])

    Сообщает об ошибке $message если файл указанный $expectedFile не содержит строки $actualString .

    assertStringNotEqualsFile() утверждает обратное и принимает тот же набор аргументов.


    Пример 4.52. Использование assertStringEqualsFile()

    assertStringStartsWith()

    assertStringStartsWith(string $prefix, string $string[, string $message = »])

    Сообщает об ошибке $message если строка $string не начинается строкой $prefix .

    assertStringStartsNotWith() утверждает обратное и принимает тот же набор аргументов.

    Пример 4.53. Использование assertStringStartsWith()

    assertTag()

    assertTag(array $matcher, string $actual[, string $message = », boolean $isHtml = TRUE])

    Сообщает об ошибке $message если $actual не соответствует спецификации $matcher .

    $matcher — это ассоциативный массив который описывает критерии соответствия для допущения:

    • id : Значение которому должен быть равен аттрибут id элемента.
    • tag : Ожидаемый тип элемента.
    • attributes : Аттрибуты элемента должны совпадать с соответствующими значениями в ассоциативном массиве $attributes .
    • content : Текстовое содержимое элемента должно совпадать со значением этого ключа массива.
    • parent : Родитель элемента должен совпадать с описаным в ассоциативном масиве $parent .
    • child : Хотя бы один прямой потомок элемента должен соответствовать критериям ассоциативного массива $child .
    • ancestor : Хотя бы один из предков элемента должен соответствовать критериям из массива $ancestor .
    • descendant : Хотя бы один из потомков (включая непрямых) должен соответствовать критериям из массива $descendant .
    • children : Ассоциативный массив количества прямых потомков
    • count : Количество потомков должно быть равно этому числу.
    • less_than : Количество потомков должно быть меньше этого числа.
    • greater_than : Количество потомков должно быть больше этого числа.
    • only : Еще один ассоциативный массив состоящий из ключей соответствующих потомкам и только соответствующие потомки будут учтены.

    assertNotTag() утверждает обратное и принимает тот же набор аргументов.

    Пример 4.54. Использование assertTag()

    assertThat()

    Более сложные утверждения могут быть сформулированы с использованием классов PHPUnit_Framework_Constraint . Они могут быть вычислены с использованием метода assertThat() . Пример 4.55, «Использование assertThat()» показывает как с помощью условий logicalNot() и equalTo() можно выразить то же утверждение что и с помощью assertNotEquals() .

    assertThat(mixed $value, PHPUnit_Framework_Constraint $constraint[, $message = »])

    Сообщает об ошибке $message если значение $value не соответствует условию $constraint .

    Пример 4.55. Использование assertThat()

    Таблица 4.3, «Условия» показывает набор доступных под-классов PHPUnit_Framework_Constraint .

    Таблица 4.3. Условия

    Условие Значение
    PHPUnit_Framework_Constraint_Attribute attribute(PHPUnit_Framework_Constraint $constraint, $attributeName) Условие которое применяет другое условие к класса или объекта.
    PHPUnit_Framework_Constraint_IsAnything anything() Этому условию удовлетворяет любое входное значение.
    PHPUnit_Framework_Constraint_ArrayHasKey arrayHasKey(mixed $key) Этому условию соответствует массив содержит ключ $key .
    PHPUnit_Framework_Constraint_TraversableContains contains(mixed $value) Этому условию соответствует массив или объект предоставляющий интерфейс Iterator который содержит некоторое значение $value .
    PHPUnit_Framework_Constraint_TraversableContainsOnly containsOnly(string $type) Этому условию соответствует массив или объект предоставляющий интерфейс Iterator содержащий только значения определённого типа.
    PHPUnit_Framework_Constraint_TraversableContainsOnly containsOnlyInstancesOf(string $classname) Этому условию соответствует массив или объект предоставляющий интерфейс Iterator содержащий только экземпляры класса определённого класса.
    PHPUnit_Framework_Constraint_IsEqual equalTo($value, $delta = 0, $maxDepth = 10) Проверяет на равенство с заданной погрешностью и глубиной вложенности.
    PHPUnit_Framework_Constraint_Attribute attributeEqualTo($attributeName, $value, $delta = 0, $maxDepth = 10) Проверяет на равенство аттрибута сласса или объекта заданному значению.
    PHPUnit_Framework_Constraint_FileExists fileExists() Проверяет что файл с таким именем существует.
    PHPUnit_Framework_Constraint_GreaterThan greaterThan(mixed $value) Этому условию соответствует значение большее чем некое заданное $value.
    PHPUnit_Framework_Constraint_Or greaterThanOrEqual(mixed $value) Этому условию соответствует значение большее либо равное заданному $value.
    PHPUnit_Framework_Constraint_ClassHasAttribute classHasAttribute(string $attributeName) Этому условию соответствует класс содержащий заданный аттрибут.
    PHPUnit_Framework_Constraint_ClassHasStaticAttribute classHasStaticAttribute(string $attributeName) Этому условию соответствует класс содержащий заданный статический аттрибут.
    PHPUnit_Framework_Constraint_ObjectHasAttribute hasAttribute(string $attributeName) Этому условию соответствует объект содержащий заданный аттрибут.
    PHPUnit_Framework_Constraint_IsIdentical identicalTo(mixed $value) Этому условию соответствуют полностью идентичные значения.
    PHPUnit_Framework_Constraint_IsFalse isFalse() Этому условию соответствует переменная когда она равна логическому FALSE .
    PHPUnit_Framework_Constraint_IsInstanceOf isInstanceOf(string $className) Этому условию соответствует объект являющийся экземпляром заданного класса.
    PHPUnit_Framework_Constraint_IsNull isNull() Этому условию соответствует переменная когда она равна NULL .
    PHPUnit_Framework_Constraint_IsTrue isTrue() Этому условию соответствует переменная когда она равна логическому TRUE .
    PHPUnit_Framework_Constraint_IsType isType(string $type) Этому условию соответствует переменная когда она принадлежит к заданному типу.
    PHPUnit_Framework_Constraint_LessThan lessThan(mixed $value) Этому условию соответствует значение меньшее чем некое заданное $value.
    PHPUnit_Framework_Constraint_Or lessThanOrEqual(mixed $value) Этому условию соответствует значение меньшее либо равное заданному $value.
    logicalAnd() Логическое И.
    logicalNot(PHPUnit_Framework_Constraint $constraint) Логическое НЕ.
    logicalOr() Логическое ИЛИ.
    logicalXor() Логическое взаимоисключающее ИЛИ.
    PHPUnit_Framework_Constraint_PCREMatch matchesRegularExpression(string $pattern) Проверяет соответствие строки заданному регулярному выражению.
    PHPUnit_Framework_Constraint_StringContains stringContains(string $string, bool $case) Проверяет что заданная подстрока содержится в строке.
    PHPUnit_Framework_Constraint_StringEndsWith stringEndsWith(string $suffix) Проверяет что строка оканчивается на заданный суфикс.
    PHPUnit_Framework_Constraint_StringStartsWith stringStartsWith(string $prefix) Проверяет что строка начинается с заданного префикса.

    assertTrue()

    assertTrue(bool $condition[, string $message = »])

    Сообщает об ошибке $message если $condition равно логическому FALSE .

    Пример 4.56. Использование assertTrue()

    assertXmlFileEqualsXmlFile()

    assertXmlFileEqualsXmlFile(string $expectedFile, string $actualFile[, string $message = »])

    Сообщает об ошибке $message если XML документ в файле $actualFile не равен XML документу из файла $expectedFile .

    assertXmlFileNotEqualsXmlFile() утверждает обратное и принимает тот же набор аргументов.

    Пример 4.57. Использование assertXmlFileEqualsXmlFile()

    assertXmlStringEqualsXmlFile()

    assertXmlStringEqualsXmlFile(string $expectedFile, string $actualXml[, string $message = »])

    Сообщает об ошибке $message если XML документ в строке $actualXml не равен XML документу из файла $expectedFile .

    assertXmlStringNotEqualsXmlFile() утверждает обратное и принимает тот же набор аргументов.

    Пример 4.58. Использование assertXmlStringEqualsXmlFile()

    assertXmlStringEqualsXmlString()

    assertXmlStringEqualsXmlString(string $expectedXml, string $actualXml[, string $message = »])

    Сообщает об ошибке $message если XML документ в строке $actualXml не равен XML документу в строке $expectedXml .

    assertXmlStringNotEqualsXmlString() утверждает обратное и принимает тот же набор аргументов.

    Пример 4.59. Использование assertXmlStringEqualsXmlString()

    Инструмент для автоматического создания тестов PHPUnit?

    Мне было интересно — есть ли инструмент, который будет смотреть на мой PHP-код и автоматически генерировать для него тест PHPUnit? Или есть ли такой инструмент для любого другого языка, который я мог бы переносить на PHP?

    Я не говорю о создании скелета. Я думал, что будет возможно, чтобы инструмент мог смотреть на токенизированный PHP и определять пути кода через метод, а затем автоматически генерировать тест для каждого пути кода, создавая mocks и устанавливая «ожидающие» вызовы по мере необходимости.

    Даже если нет инструмента, который в настоящее время это делает, может ли такая задача быть осуществимой или я что-то не замечаю?

    Оказывается, нет инструмента, который делает это в настоящее время, поэтому я написал один (с помощью моих коллег). Не полный — достаточно, чтобы исследовать концепцию. Используя nikic PHP-Parser (https://github.com/nikic/PHP-Parser), можно найти все вызовы методов в методах класса, а затем mocks может быть создан для них.

    По крайней мере, я, возможно, в конечном итоге доберусь до такой степени, что смогу использовать его для выполнения отдельных тестовых тестов.

    Вряд ли возможно.

    Современные методы автоматической генерации тестов зависят от наличия спецификаций для поведения кода, а не только для реализации. Вывод спецификации из PHP-кода не всегда легко для человека, не говоря уже о машине, поэтому я серьезно сомневаюсь, что можно было бы сделать эту работу для любого реального кода.

    Автоматизированное тестирование с PHP

    Я разработчик .net, так что извините за то, что я ничего не знаю о PHP . Я читал некоторые вещи в сети, но я не могу сказать, как это сравнивается с Asp.net MVC с точки зрения автоматического тестирования.

    Я склонен думать, что PHP очень похож на классический ASP, за исключением того, что это ООП (не так ли?). Чтобы улучшить его тестируемость, вы должны следовать определенным шаблонам разработки и стилю кода, чтобы обеспечить SoC (аналогично Asp.net WebForm, где вы, например, должны выполнять MVP, но вы все еще на расстоянии световых лет от того, что Asp.net MVC дает вам). из коробки).

    Так. Как PHP сравнивается с Asp.net MVC с точки зрения написания автоматических тестов (особенно, конечно, модульных тестов)? Должен ли я использовать определенные библиотеки? Должен ли я следовать определенным правилам / шаблонам, чтобы это работало?

    Как насчет непрерывной интеграции? Может ли тест там быть запущен автоматически?

    3 ответа

    В зависимости от ситуации я использую три: SimpleTest, PHPUnit и Zend_Test (на самом деле это просто оболочка для PHPUnit для использования с Zend Framework). Из них SimpleTest действительно проще. Тем не менее, PHPUnit обеспечивает большую мощность и гибкость.

    Я не разработчик .net, поэтому я не могу сравнить их, но я могу помочь заполнить несколько пробелов в PHP.

    Во-первых, хотя PHP поддерживает классы и ООП, как вы привыкли, в этом нет необходимости. На самом деле, некоторые проекты на основе PHP (такие как Drupal) практически не содержат ОО-кода.

    Что касается тестирования PHP-кода, вы, вероятно, захотите использовать PHPUnit. Он реализует систему xUnit для тестирования кода на PHP. Но если PHPUnit вам не нравится, то вы можете попробовать SimpleTest, немного другую среду тестирования PHP.

    php не сравнивается с asp.net mvc, так как php — это язык, подобный c # У них обоих есть OO, и вы можете тестировать методы и классы, как вы делаете в asp.net

    Так же, как в asp.net у вас есть mvc в php тоже. Возможно, вы захотите взглянуть на некоторые фреймворки, такие как Symfony, которые работают на той же модели mvc.

    Тестирование в .net выполняется с помощью NUnit или других, в PHP у вас есть несколько симуляторов, таких как PHPUnit, а в Symfony также есть Lime.

    на самом деле, я нахожусь в oposit ситуации, пришедшей из php, а сейчас в разработке на c #, и все это почти то же самое .

    тесты могут быть запущены автоматически, в .net вы, возможно, знаете nant (инструмент автоматического тестирования и сборки), ant — то же самое для php / java и hudson как инструмент для получения обзора всех сборок.

    Добавить комментарий