PHPUnit Как каждый раз проверять разные переменные?

Я пишу класс продукта, задача класса - принять продукт id и вывести соответствующий продукт name.

Например:

$Product = new Product;
$Product->id = "ff62";
$Product->readId();
echo $Product->name;

// returns a string with at least 5 characters.

Мой тестовый метод PHPUnit выглядит так:

$Product = new Product;
$Product->id = "ff62"; // needs to be a variable
$Product->readId();
$this->assertEquals(gettype($Product->name), 'string');

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

В идеале нужно уметь определять переменную id во время тестирования.

Как лучше всего тестировать динамические переменные как таковые?

echo dechex(255).dechex(98);
Lawrence Cherone 12.09.2018 12:31

Я бы подумал, что вам понадобится набор фиксированных идентификаторов продукта, чтобы вы могли проверить, ожидаете ли вы, что элемент существует, какими должны быть другие поля и т. д.

Nigel Ren 12.09.2018 12:45

@NigelRen, вы хотите сказать, что лучше всего тестировать на фиксированном наборе данных. Как насчет тестирования вызовов API с использованием секретного ключа API? Мы не можем хранить ключ API в тестовом файле. Точно так же идентификатор в этом случае похож на ключ. Я хочу знать, как тестировать переменный ключ.

Donnie Ashok 12.09.2018 12:52

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

k0pernikus 12.09.2018 14:50
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
4
576
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

$value = dechex(random_int(0, 255)).dechex(random_int(0, 255));

$Product = new Product;
$Product->id = $value;
$Product->readId();
$this->assertEquals('string', gettype($Product->name));
$this->assertEquals($value, $Product->name);

Обычно ожидаемое значение помещается слева, а фактическое - справа.

Я выяснил, что лучший способ сделать это - использовать Faker.

https://github.com/fzaninotto/Faker

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

Хотя в основном используется в Laravel, Symfony и т. д., Его довольно легко использовать даже в пользовательских фреймворках PHP.

Ответ принят как подходящий

Faker - это один из способов сделать это, но я не решусь сказать, что это «лучший способ».

Ваши требования: 1. Протестируйте набор различных переменных. 2. Эти переменные могут существовать или не существовать в базе данных.

Но у вас есть несколько проблем с тем, как вы разработали этот тест:

  1. Вы используете gettype() и сравниваете его со строкой. Это плохая идея. Если продукт 54 равен «foo», а ваш тест возвращает «bar» для 54, он будет успешным. Это Программирование по совпадению. То есть работает, но не специально.
  2. То, как вы это настраиваете, на самом деле не решает проблему. Хотя Faker может создавать поддельные данные, он не может автоматически создавать заведомо хорошие и заведомо плохие данные для вашей конкретной системы и бизнес-кейсов. Я предполагаю, что вы хотите протестировать известные хорошие данные + ожидаемые результаты, а также известные плохие данные + ожидаемые исключения.

Правильный способ структурировать этот тест - использовать @dataProvider и фикстуры базы данных / тестирование.

Вот как это будет выглядеть:

<?php
namespace Foo\Bar;

use PHPUnit\DbUnit\TestCaseTrait;
use PHPUnit\Framework\TestCase;
use \PDO;
USE \Exception;

class ProductTest extends TestCase
{
    use TestCaseTrait;


    // only instantiate pdo once for test clean-up/fixture load
    static private $pdo = null;

    // only instantiate PHPUnit_Extensions_Database_DB_IDatabaseConnection once per test
    private $conn = null;

    final public function getConnection()
    {
        if ($this->conn === null) {
            if (self::$pdo == null) {
                self::$pdo = new PDO($GLOBALS['DB_DSN'], $GLOBALS['DB_USER'], $GLOBALS['DB_PASSWD']);
            }
            $this->conn = $this->createDefaultDBConnection(self::$pdo, $GLOBALS['DB_DBNAME']);
        }

        return $this->conn;
    }

    public function getDataSet()
    {
        return $this->createMySQLXMLDataSet('tests/unit/testdata/sampleproductdata.xml');
    }

    /**
     * Tests products against known good data in the database fixture.
     * @param $id
     * @param $expectedName
     * @dataProvider providerTestProduct
     */

    public function testProduct($id, $expectedName) {
        $Product = new Product;
        $Product->id = $id;
        $Product->readId();
        $this->assertSame($expectedName, $Product->name);
    }

    /**
     * Provides data that should appear in the database.
     * @return array
     */
    public function providerTestProduct() {
                // id , expectedName
        return  [ [ "ff62" , "fooproduct"]
                , [ "dd83" , "barproduct"]
                , [ "ls98" , "bazproduct"]
                ];
    }

    /**
     * Tests products against known-bad data to ensure proper exceptions are thrown.
     * @param $id
     * @param $expectedName
     */
    public function testProductExceptions($id, $expectedName) {
        $Product = new Product;
        $Product->id = $id;

        $this->expectException(Exception::class);
        $Product->readId();
    }

    /**
     * Provides test data that when queried against the database should produce an error.
     * @return array
     */
    public function providerTestProductExceptions() {
        // id , expectedName
        return  [ [ "badtype" , "fooproduct"]  //Wrong id type
                , [ "aaaa" , "barproduct"]     //Does not exist
                , [ null   , "bazproduct"]     //null is a no-no.
        ];
    }
}

Вот разбивка:

  1. Используйте пространства имен. Потому что сейчас 2018 год, а это правильный поступок.
  2. Используйте use, чтобы объявить, какие классы вы используете в тесте.
  3. Используйте TestCaseTrait для правильного настроить свой TestCase
  4. Частная переменная $pdo будет содержать ваше соединение с базой данных для вашего класса / теста.
  5. Требуется getConnection(). Это будет использовать базу данных, имя пользователя и пароль, которые вы настроили в вашем файле phpunit.xml. Ссылка
  6. getDataSet() читает ваш источник данных (прибор), затем обрезает вашу базу данных на вашей рабочей станции / блоке разработчика, импортирует все данные из прибора, чтобы перевести базу данных в известное состояние. (Обязательно сделайте резервную копию своих данных, прежде чем делать это. Это намеренно с потерями. Никогда не запускайте в производственной среде).

Далее у вас есть две пары методов для тестовых случаев: тест и поставщик данных.

Поставщик данных в каждый случай предоставляет идентификатор, который вы хотите протестировать, и ожидаемый результат. В случае testProduct и providerTestProduct мы предоставляем идентификатор, который должен существовать в базе данных (как это предусмотрено приведенным выше приспособлением). Затем мы можем проверить, что Product::readId() не только возвращает нить, но фактически возвращает правильная строка.

Во втором случае, testProductException() и providerTestProductException(), мы намеренно отправляем неверные значения в класс для запуска исключений, а затем проверяем эти неверные значения на самом деле производит желаемое поведение: сбой / выброшенные исключения.

Другие вопросы по теме