PHPUnit Как каждый раз проверять разные переменные? - PullRequest
0 голосов
/ 12 сентября 2018

Я пишу Класс Продукта, задача Класса состоит в том, чтобы взять продукт 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 во время тестирования.

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

Ответы [ 3 ]

0 голосов
/ 22 сентября 2018

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

https://github.com/fzaninotto/Faker

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

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

0 голосов
/ 26 сентября 2018

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

Ваши требования: 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() идет и читает ваш источник данных (фикстур), затем усекает вашу базу данных на вашей рабочей станции / dev, импортирует все данные из фикстура, чтобы вывести базу данных в известное состояние. (Обязательно сделайте резервную копию своих данных, прежде чем сделать это. Это специально с потерями. Никогда не выполняйте на производстве).

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

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

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

0 голосов
/ 13 сентября 2018

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

$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);

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

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