Поставщики данных вызываются до выполнения статического setupBeforeClass
. Если подумать, должно быть наоборот.
Пример использования:
setupBeforeClass
и заставить поставщик вернуть это свойство.Проблема в том, что свойство не инициализируется при вызове провайдера.
Найденная версия: 3.7.14
Я не уверен, что обеспечение некоторого порядка, чтобы статические ресурсы могли быть инициализированы в setupBeforeClass
действительно имеет смысл, если вы считаете, что поставщики данных не обязательно должны быть статическими или даже в том же тестовом классе.
Почему бы просто не инициализировать адаптеры лениво? Тогда порядок вообще не имеет значения.
Без запуска поставщика данных мы не знаем, сколько тестов запускает метод тестирования. В идеальном мире мы нарушили бы B / C и потребовали бы, чтобы поставщики данных были объектами, реализующими интерфейс, расширяющий Countable
. Таким образом, мы могли бы разделить эти проблемы и получить более чистую ситуацию.
@whatthejeff Это то, чем мы в конечном итоге занимаемся. Однако инициализация в конструкторе могла бы быть немного чище, потому что параметры должны быть заключены в массив при возврате от поставщика.
@sebastianbergmann, хорошо, я понимаю, почему они называются раньше, как насчет упоминания об этом в документе? (Я могу открыть PR, который меняет, если вы в порядке). Я даже не уверен, что наличие объектов могло бы сильно помочь: если вы посмотрите на моего бывшего, есть зависимость от одного поставщика к другому.
Спасибо за ответы, закрытие вопроса.
@vicb , я с радостью
Я мог бы быть немного опоздал на сцену, но то , что я случайно делать , когда у меня есть зависимость , которые мне нужно инициализировать, чтобы угробить @dataProvider
аннотации и использовать yield
вместо этого.
@srosato Я https://gist.github.com, если пример здесь не подходит.
Если для вашего @dataProvider
требуется установочный код и они не очень большие, вы можете указать их как строки и eval
в тесте. Например:
public function myProvider() {
return [
'new Klass("param 1", "param 2")',
'new Klass("param 1", "param 2")',
];
}
/**
* <strong i="8">@dataProvider</strong> myProvider
*/
public testMyFunction($instance_str) {
$klass = eval("return {$instance_str};");
# continue testing $klass ...
}
мои два цента:
Вместо поставщика данных, полагающегося на статическое свойство (которое, как мы знаем, невозможно), я устанавливаю необходимые данные / объекты как члены класса тестового класса в методе setUp()
.
в tearDown()
я устанавливаю для него / них значение null, или когда есть сложные объекты, я реализую для него метод clear()
.
пока не существует слишком большого количества зависимостей для всего тестового класса, я чувствую себя комфортно с этим подходом.
но когда таких зависимостей больше одной или двух, вам, возможно, придется переосмыслить свой общий дизайн.
в частности, я использую соединение с БД как статическое свойство, которое установлено в setUpBeforeClass()
и устанавливаю $queryBuilder
, которое вводит соединение, как член класса в setUp()
(вместо возвращая его в провайдере данных).
Решением было бы определить новый частный метод и определить столько переменных, сколько необходимо, как static
внутри него. Затем проверьте, установлен ли один из них, а если нет, установите их все и верните (или отдайте) их. Таким образом, переменные будут объявлены только один раз, даже если у вас есть десять провайдеров или что-то еще. Кроме того, вы можете использовать его в setUpBeforeClass()
или setUp()
.
Посмотрите на примере:
private static function getData()
{
static $data, $anotherData;
if (!isset($data)) {
$data = new TestClass();
$anotherData = [];
}
return [
$data,
// Or: clone $data
$anotherData,
];
}
public static function setUpBeforeClass()
{
list(self::$sampleJson, self::$sampleData) = self::getData();
}
public function sampleProvider()
{
$data = self::getData();
return [
$data
];
}
@MAChitgarha, вчера благодаря вашему комментарию, я узнал об этом билете. :)
Я работаю над рефакторингом логики поставщика данных в # 3736, который решит некоторые из распространенных проблем:
setUpBeforeClass
и setUp
@epdenouden Приятно это слышать! ;) Второй пункт в вашем списке хороший. Жду этого.
Возможны нестатические поставщики данных
Разве сейчас это невозможно? Я всегда использую нестатические поставщики данных в своих тестах вместо статических, и они работают, как ожидалось, без проблем (с использованием PHPUnit 7.5.6). Я ошибся?
Разве сейчас это невозможно? Я всегда использую нестатические поставщики данных в своих тестах вместо статических, и они работают, как ожидалось, без проблем (с использованием PHPUnit 7.5.6). Я ошибся?
Нет, ты прав! Моя фраза была недостаточно точной, спасибо, что подняли этот вопрос. Глубоко внутри кода обработки поставщика данных он в настоящее время читает:
private static function getDataFromDataProviderAnnotation($allTheParameters): ?iterable
// code for locating the data provider
// [...]
if ($dataProviderMethod->isStatic()) {
$object = null;
} else {
$object = $dataProviderClass->newInstance();
}
// code for preparing returned data rows
// [...]
}
Итак, вот маленький грязный секрет:
instanceof
но ...Вы дали мне что-то подумать и проверить в отношении рефакторинга поставщика данных! Мне нужно добавить дополнительные тесты, чтобы убедиться, что экземпляры объекта являются ожидаемыми, а не только одного типа или клона. ☕️ и 🍰 на меня, когда ты в Амстердаме.
@MAChitgarha Экземпляры действительно разные: https://github.com/epdenouden/phpunit/blob/4718e0bb470170b2da46bf0e05b7275110a2a29d/tests/_files/DataProviderInstanceTest.php#L14 -L27
@epdenouden Но у меня не бывает сбоев! В PHPUnit 7.5.13 утверждение не генерирует ошибок. Как вы получили эту ошибку? Вы имеете в виду обратную несовместимость?
Это в ветке поставщика данных с отложенной загрузкой, над которой я работаю, которая основана на версии 8.2. Дальше я проверю 7.5.x, спасибо за предупреждение.
Если это сработает, мне придется вернуться к некоторым другим более старым проблемам, которые явно просили реализовать нестатические методы поставщика, и снова взглянуть на точные варианты использования.
В любом случае: ваш комментарий уже вдохновил на очень полезный тест :)
И @MAChitgarha, да, это будет BC-break
@epdenouden Я подожду этого. По некоторым причинам в моем проекте я использую PHPUnit 7.5.13; но я скоро обновлю его до 8.2. *. И хорошие новости, если удастся устранить обрыв БК. Я не знаю структуру самого PHPUnit, поэтому не знаю, что вы изменили, но я думаю, что это можно исправить. Однако все зависит от вас! :)
И хорошие новости, если удастся устранить обрыв БК. Я не знаю структуру самого PHPUnit, поэтому не знаю, что вы изменили, но я думаю, что это можно исправить. Однако все зависит от вас! :)
@Sebastianbergmann не допускает
Итак, да, расскажите, пожалуйста, что вы хотели бы видеть как конечный пользователь / разработчик тестов. Просто имейте в виду, что у таких проектов нет большого пула разработчиков-добровольцев.
Интересный факт: приведенный выше тест действительно работает в версиях 7.x и 8.x и не работает на прототипе JIT.
Код, над которым я работаю, все еще больше похож на исходный поток кода. Так что это может быть результатом ошибки, какая-то логика, которую мне все еще нужно реорганизовать, что-то низкоуровневое об объектах и отражении в PHP, которое мне нужно найти, или, может быть, просто какое-то наивное тестирование с моей стороны. 🔬
@epdenouden JIT? Вы тестируете с помощью JIT для PHP, или я чего-то не знаю? Извините, я немного запутался; вы говорите о PHP7.x и PHP8.x или PHPUnit7.x и PHPUnit8.x ?!
@epdenouden JIT? Вы тестируете с помощью JIT для PHP, или я чего-то не знаю? Извините, я немного запутался; вы говорите о PHP7.x и PHP8.x или PHPUnit7.x и PHPUnit8.x ?!
@MAChitgarha Я понимаю ваше замешательство, поскольку PHP8 получает своевременный _компилятор_. Я использовал термин для реализации нового поставщика данных, который основан на той же идее: своевременный _loader_, также известный как ленивая загрузка. Инициализируйте только то, что вам нужно, когда вам это нужно.
Это будет нормально работать с грядущей версией PHP 8 JIT, поскольку она не использует никаких сложных функций самого языка PHP. Вся моя работа глубоко внутри PHPUnit, переделывая такие вещи, как синтаксический анализ конфигурации, тестовая загрузка и запуск и т. Д.
Если кажется, что я ничего не делаю, значит, делаю правильно. За исключением этого заниженного счета GCP или AWS. 💸
Самый полезный комментарий
@MAChitgarha Я понимаю ваше замешательство, поскольку PHP8 получает своевременный _компилятор_. Я использовал термин для реализации нового поставщика данных, который основан на той же идее: своевременный _loader_, также известный как ленивая загрузка. Инициализируйте только то, что вам нужно, когда вам это нужно.
Это будет нормально работать с грядущей версией PHP 8 JIT, поскольку она не использует никаких сложных функций самого языка PHP. Вся моя работа глубоко внутри PHPUnit, переделывая такие вещи, как синтаксический анализ конфигурации, тестовая загрузка и запуск и т. Д.
Если кажется, что я ничего не делаю, значит, делаю правильно. За исключением этого заниженного счета GCP или AWS. 💸