PHPUnit:如何为多个if-else/factory进行单元测试?



我有一个类ParentIdResolver,它根据类型返回产品的父id。
这个类看起来像:

<?php
namespace AppModel;
use AppModelProductBundle;
use AppModelProductConfigurable;
use AppModelProductDownloadable;
class ParentIdResolver
{
/**
* @var Bundle
*/
private $bundle;
/**
* @var Configurable
*/
private $configurable;
/**
* @var Downloadable
*/
private $downloadable;
public function __construct(
Bundle $bundle,
Configurable $configurable,
Downloadable $downloadable
) {
$this->bundle = $bundle;
$this->configurable = $configurable;
$this->downloadable = $downloadable;
}
public function getParentId($productId, $productType)
{
$parentIds = [];
if ($productType == 'bundle') {
$parentIds = $this->bundle->getParentIdsByChild($productId);
} elseif ($productType == 'configurable') {
$parentIds = $this->configurable->getParentIdsByChild($productId);
} elseif ($productType == 'downloadable') {
$parentIds = $this->downloadable->getParentIdsByChild($productId);
}
return $parentIds[0] ?? null;
}
}

我正试图测试getParentId()作为:

<?php
namespace AppTestUnit;
use PHPUnitFrameworkTestCase;
use AppModelParentIdResolver;
use AppModelProductBundle;
use AppModelProductConfigurable;
use AppModelProductDownloadable;
class ParentIdResolverTest extends TestCase
{
protected $model;
protected $bundleMock;
protected $configurableMock;
protected $downloadableMock;
public function setUp(): void
{
$this->bundleMock = $this->createPartialMock(
Bundle::class,
['getParentIdsByChild']
);
$this->configurableMock = $this->createPartialMock(
Configurable::class,
['getParentIdsByChild']
);
$this->downloadableMock = $this->createPartialMock(
Downloadable::class,
['getParentIdsByChild']
);
$this->model = new ParentIdResolver(
$this->bundleMock,
$this->configurableMock,
$this->downloadableMock
);
}
/**
* @dataProvider getParentIdDataProvider
*/
public function testGetParentId($productId, $productType, $parentId)
{
if ($productType == 'bundle') {
$this->bundleMock->expects($this->any())
->method('getParentIdsByChild')
->willReturn([$parentId]);
}
if ($productType == 'configurable') {
$this->configurableMock->expects($this->any())
->method('getParentIdsByChild')
->willReturn([$parentId]);
}
if ($productType == 'downloadable') {
$this->downloadableMock->expects($this->any())
->method('getParentIdsByChild')
->willReturn([$parentId]);
}
$this->assertEquals($parentId, $this->model->getParentId($productId, $productType));
}
public function getParentIdDataProvider()
{
return [
[1, 'bundle', 11],
[2, 'configurable', 22],
[3, 'downloadable', 33],
];
}
}

我不觉得我这样做是正确的,也许我需要重构主类?
请建议您在这种情况下如何重构或编写单元测试。

我个人会考虑将解析正确类的责任转移给每个类本身。有些人称之为"问,不要说"。它看起来像这样

<?php
namespace AppModel;
use AppModelProductResolvesParentId;
class ParentIdResolver
{
/** @var ResolvesParentId[] */
private $parentIdResolvers;
public function __construct(array $parentIdResolvers)
{
$this->parentIdResolvers = $parentIdResolvers;
}
public function getParentId(int $productId, string $productType): int
{
foreach ($this->parentIdResolvers as $parentIdResolver) {
if ($parentIdResolver->supports($productType)) {
return $parentIdResolver->getParentId($productId)[0] ?? null;
}
}
return null;
}
}
<?php
namespace AppModelProduct;
interface ResolvesParentId
{
public function supports(string $productType): bool;
public function getParentIdsByChild(int $productId): array;
}
<?php
namespace AppModelProduct;
class Bundle implements ResolvesParentId
{
public function supports(string $productType): bool
{
return $productType === 'bundle';
}
public function getParentIdsByChild(int $productId): array
{
// Your implementation here.
}
}
<?php
namespace AppModelProduct;
class Configurable implements ResolvesParentId
{
public function supports(string $productType): bool
{
return $productType === 'configurable';
}
public function getParentIdsByChild(int $productId): array
{
// Your implementation here.
}
}
<?php
namespace AppModelProduct;
class Downloadable implements ResolvesParentId
{
public function supports(string $productType): bool
{
return $productType === 'downloadable';
}
public function getParentIdsByChild(int $productId): array
{
// Your implementation here.
}
}

有些人认为这太过分了,这完全取决于你所处的情况。你认为if/else在未来会增长吗?那么这个解决方案可能适合您。

最新更新