您可以对此类变体使用@dataProvider 注释。在下面找到一个示例,您可以在其中指定类列表,并且将为所有人运行相同的测试。
class ISortableImplementationsTest extends TestCase
{
/**
* @dataProvider getImplementationClass
*/
public function testSort(string $implClass): void
{
//First make sure if the class actually implements the interface.
//This assertion is not required if you added the list of classes manually
$this->assertTrue(
in_array(ISortable::class, class_implements($implClass)),
sprintf(
"Test Failed. The class %s does not implement the expected interface %s.",
$implClass,
ISortable::class
)
);
// Now the real test of implementation begins here
$unsorted = ['s', 'a', 'd'];
$subjectClassObject = new $implClass($unsorted);
$result = $subjectClassObject->sort();
$this->assertEquals(
['a', 'd', 's'],
$result,
sprintf(
"Test for class %s failed. Given %s. Expected %s. Got %s.",
$implClass,
print_r($unsorted, true),
print_r(['a', 'd', 's'], true),
print_r($result, true)
)
);
}
public function getImplementationClass() : array
{
return [
[ ISortableImplementaionClass1::class ],
[ ISortableImplementaionClass2::class ],
];
}
}
更进一步,您可能可以使用these 方法之一来自动加载整个类列表。以上代码在 PHP 7.4 上测试。
但是,我不建议对 Clean Code 进行上述测试。通常,每个单元测试都指向代码中的一个类。它的好处是您可以随时返回并进行单元测试并相应地进行更改。我知道仅测试行为很好,但有时您也只想在特殊情况下测试实现。
我更喜欢使用模板方法模式进行单元测试,基类包含所有常见的内容,以及提供所有特定内容的扩展。
abstract class ISortableTestTemplate extends TestCase
{
abstract protected function getISortableInstance(array $unsorted): ISortable;
public function testSort(): void
{
$unsorted = ['s', 'a', 'd'];
$subjectClassObject = $this->getISortableInstance($unsorted);
$result = $subjectClassObject->sort();
$this->assertEquals(
['a', 'd', 's'],
$result,
sprintf(
"Test failed. Given %s. Expected %s. Got %s.",
print_r($unsorted, true),
print_r(['a', 'd', 's'], true),
print_r($result, true)
)
);
}
}
class ISortableImplementationClass1Test extends ISortableTestTemplate
{
protected function getISortableInstance(array $unsorted): ISortable
{
return new ISortableImplementaionClass1($unsorted);
}
public function testSort(): void
{
parent::testSort();
}
}