Я пишу класс продукта, задача класса - принять продукт 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 во время тестирования.
Как лучше всего тестировать динамические переменные как таковые?
Я бы подумал, что вам понадобится набор фиксированных идентификаторов продукта, чтобы вы могли проверить, ожидаете ли вы, что элемент существует, какими должны быть другие поля и т. д.
@NigelRen, вы хотите сказать, что лучше всего тестировать на фиксированном наборе данных. Как насчет тестирования вызовов API с использованием секретного ключа API? Мы не можем хранить ключ API в тестовом файле. Точно так же идентификатор в этом случае похож на ключ. Я хочу знать, как тестировать переменный ключ.
Чего вы пытаетесь достичь? В рамках модульного теста ваши тестовые данные должны быть фиксированными или, по крайней мере, известными. Следует исключить внешние зависимости API или баз данных, оставив для тестирования только бизнес-логику.






Вы можете рандомизировать свой набор данных, используя генерацию случайных чисел.
$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. Эти переменные могут существовать или не существовать в базе данных.
Но у вас есть несколько проблем с тем, как вы разработали этот тест:
gettype() и сравниваете его со строкой. Это плохая идея. Если продукт 54 равен «foo», а ваш тест возвращает «bar» для 54, он будет успешным. Это Программирование по совпадению. То есть работает, но не специально.Правильный способ структурировать этот тест - использовать @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.
];
}
}
Вот разбивка:
use, чтобы объявить, какие классы вы используете в тесте.TestCaseTrait для правильного настроить свой TestCase$pdo будет содержать ваше соединение с базой данных для вашего класса / теста.getConnection(). Это будет использовать базу данных, имя пользователя и пароль, которые вы настроили в вашем файле phpunit.xml. СсылкаgetDataSet() читает ваш источник данных (прибор), затем обрезает вашу базу данных на вашей рабочей станции / блоке разработчика, импортирует все данные из прибора, чтобы перевести базу данных в известное состояние. (Обязательно сделайте резервную копию своих данных, прежде чем делать это. Это намеренно с потерями. Никогда не запускайте в производственной среде).Далее у вас есть две пары методов для тестовых случаев: тест и поставщик данных.
Поставщик данных в каждый случай предоставляет идентификатор, который вы хотите протестировать, и ожидаемый результат. В случае testProduct и providerTestProduct мы предоставляем идентификатор, который должен существовать в базе данных (как это предусмотрено приведенным выше приспособлением). Затем мы можем проверить, что Product::readId() не только возвращает нить, но фактически возвращает правильная строка.
Во втором случае, testProductException() и providerTestProductException(), мы намеренно отправляем неверные значения в класс для запуска исключений, а затем проверяем эти неверные значения на самом деле производит желаемое поведение: сбой / выброшенные исключения.
echo dechex(255).dechex(98);