Den*_*nis 1 php phpunit unit-testing php-7
我究竟如何为使用实时数据库的方法编写测试?
考虑这个代码:
class PricingRepository extends GenericRepository
{
public function getOptionPrice(int $productId, int $quantity, float $productPrice = 0.0): float
{
//retrieves option record for a given product
$row = $this->getMySql()->paramQuery("
select * from pricing
where product_id = ?", array(
$productId
))->getSingleArray();
//based on pricing type computes appropriate value
if ($row['pricing_type'] === 'Quantity-based')
return $row['base'] + $row['amount_per_quantity'] * $quantity;
if ($row['pricing_type'] === 'Percentage-based')
return $productPrice * $row['percentage'];
throw new \InvalidArgumentException("invalid pricing type detected");
}
}
Run Code Online (Sandbox Code Playgroud)
我有很多像上面那样的方法,所以我想确保我的测试是可靠的,并且不会在数据库数据发生变化时发生变化。我正在寻找关于一流单元测试方法的建议/解决方案,以及一种可能不依赖于数据库中数据更改的方法。
我现在编写一个简单的单元测试的方式可能是这样的:
use PHPUnit\Framework\TestCase;
class OptionPricingTest extends TestCase
{
function setUp()
{
$this->pricingRepository = new PricingRepository();
}
function testOptionPricing()
{
$actual_option_price = $this->pricingRepository->getOptionPrice(111, 1, 100);
$this->assertEquals(10.0, $actual_option_price);
}
}
Run Code Online (Sandbox Code Playgroud)
但是如果数据或定价类型发生变化,我的测试也必须改变。
存储库的设计使其难以测试。
考虑不要在存储库类中创建数据库连接,而是通过构造函数注入它。
interface DBInterface
{
public function paramQuery($query, array $params = []): DBInterface;
public function getSingleArray(): array;
// ...
}
class GenericRepository
{
/** @var DBInterface */
private $mysql;
public function __construct(DBInterface $mysql)
{
$this->mysql = $mysql;
}
protected function getMySql(): DBInterface
{
return $this->mysql;
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
然后很容易注入一个模拟对象。
对于上面的测试用例,模拟可能如下所示:
class MysqlMock implements DBInterface
{
private $resultSet = [];
private $currentQuery;
private $currentParams;
public function paramQuery($query, array $params = []): DBInterface
{
$this->currentId = array_shift($params);
}
public function getSingleArray(): array
{
return $this->resultSet[$this->currentId];
}
public function setResultSet($array records)
{
$this->resultSet = $records;
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
这样,您就独立于价格的实际变化和产品的移除。如果您的数据结构发生变化,您只需更改测试。
use PHPUnit\Framework\TestCase;
class OptionPricingTest extends TestCase
{
private $pricingRepository;
private $mysqlMock;
public function setUp()
{
$this->mysqlMock = new MysqlMock;
$this->pricingRepository = new PricingRepository($this->mysqlMock);
}
public function testOptionPricing()
{
$this->mysqlMock->setResultSet([
111 => [
'pricing_type' => 'Quantity-based',
'base' => 6,
'amount_per_quantity' => 4,
]
]);
$actual_option_price = $this->pricingRepository->getOptionPrice(111, 1, 100);
$this->assertEquals(10.0, $actual_option_price);
}
}
Run Code Online (Sandbox Code Playgroud)