Phpunit: Поставщики данных выполняются перед setupBeforeClass

Созданный на 21 февр. 2013  ·  21Комментарии  ·  Источник: sebastianbergmann/phpunit

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

Пример использования:

  • У нас есть список адаптеров. Некоторые адаптеры поддерживаются только в определенной среде (например, Linux против Win),
  • Я хотел бы один раз инициализировать список поддерживаемых адаптеров и передать его на все тесты через поставщика данных,
  • Самый чистый способ, который я могу себе представить, - это инициализировать статическое свойство в setupBeforeClass и заставить поставщик вернуть это свойство.

Проблема в том, что свойство не инициализируется при вызове провайдера.

Найденная версия: 3.7.14

Самый полезный комментарий

@epdenouden JIT? Вы тестируете с помощью JIT для PHP, или я чего-то не знаю? Извините, я немного запутался; вы говорите о PHP7.x и PHP8.x или PHPUnit7.x и PHPUnit8.x ?!

@MAChitgarha Я понимаю ваше замешательство, поскольку PHP8 получает своевременный _компилятор_. Я использовал термин для реализации нового поставщика данных, который основан на той же идее: своевременный _loader_, также известный как ленивая загрузка. Инициализируйте только то, что вам нужно, когда вам это нужно.

Это будет нормально работать с грядущей версией PHP 8 JIT, поскольку она не использует никаких сложных функций самого языка PHP. Вся моя работа глубоко внутри PHPUnit, переделывая такие вещи, как синтаксический анализ конфигурации, тестовая загрузка и запуск и т. Д.

Если кажется, что я ничего не делаю, значит, делаю правильно. За исключением этого заниженного счета GCP или AWS. 💸

Все 21 Комментарий

Я не уверен, что обеспечение некоторого порядка, чтобы статические ресурсы могли быть инициализированы в 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 но ...
  • это _не тот же экземпляр_, который используется для приспособлений и тестов

Вы дали мне что-то подумать и проверить в отношении рефакторинга поставщика данных! Мне нужно добавить дополнительные тесты, чтобы убедиться, что экземпляры объекта являются ожидаемыми, а не только одного типа или клона. ☕️ и 🍰 на меня, когда ты в Амстердаме.

@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. 💸

Была ли эта страница полезной?
0 / 5 - 0 рейтинги