作为一名php开发者,我们深知单元测试的重要性。而phpunit作为事实上的标准测试框架,其数据提供者(data provider)功能更是让我们能够用一套测试逻辑覆盖多种输入场景,极大地提高了测试效率。然而,在实际项目中,我却常常被一个问题困扰:为各种常见数据类型(比如空字符串、空白字符串、负数、零、布尔值等)编写数据提供者时,总是不得不一遍又一遍地重复编写相似的代码。
想象一下,你正在测试一个用户注册功能,需要验证用户名不能是空字符串或只包含空格。你可能会写出这样的代码:
<pre class="brush:php;toolbar:false;"><?php
// ... 其他代码 ...
class UserTest extends \PHPUnit\Framework\TestCase
{
// ... 其他测试方法 ...
/**
* @dataProvider provideInvalidUserNames
*/
public function testUserNameCannotBeEmptyOrBlank(string $value): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Value can not be an empty or blank string.');
UserName::fromString($value);
}
public static function provideInvalidUserNames(): array
{
return [
'empty string' => [''],
'blank string with space' => [' '],
'blank string with tab' => ["\t"],
'blank string with newline' => ["\n"],
];
}
}
// 假设有一个这样的 UserName 类
final class UserName
{
private string $value;
private function __construct(string $value)
{
$this->value = $value;
}
public static function fromString(string $value): self
{
if (trim($value) === '') {
throw new \InvalidArgumentException('Value can not be an empty or blank string.');
}
return new self($value);
}
}这看起来没问题,对吧?但如果你的项目中还有十几个、几十个地方需要验证“非空非空白字符串”的逻辑呢?你就会发现自己不得不复制粘贴,或者为每个模块都创建一套几乎相同的数据提供者。这不仅导致了大量的样板代码,让测试文件变得臃肿不堪,而且一旦需要调整某个“空白字符串”的定义(比如增加一个Unicode空白字符),你就得在所有地方手动修改,维护成本极高,也容易出错。这种重复劳动,简直是开发者的噩梦!
正当我为此头疼不已时,我偶然发现了
ergebnis/data-provider
ergebnis/data-provider
立即学习“PHP免费学习笔记(深入)”;
使用
ergebnis/data-provider
<pre class="brush:php;toolbar:false;">composer require ergebnis/data-provider
安装完成后,你就可以在你的 PHPUnit 测试中直接引用它提供的各种数据提供者了。让我们回到之前那个“用户名不能是空字符串或空白字符串”的例子,使用
ergebnis/data-provider
<pre class="brush:php;toolbar:false;"><?php
declare(strict_types=1);
namespace Example\Test;
use Ergebnis\DataProvider;
use PHPUnit\Framework;
use InvalidArgumentException; // 假设 UserName::fromString 抛出此异常
// 假设有一个这样的 UserName 类
final class UserName
{
private string $value;
private function __construct(string $value)
{
$this->value = $value;
}
public static function fromString(string $value): self
{
if (trim($value) === '') {
throw new InvalidArgumentException('Value can not be an empty or blank string.');
}
return new self($value);
}
}
final class ExampleTest extends Framework\TestCase
{
/**
* @dataProvider \Ergebnis\DataProvider\StringProvider::blank()
* @dataProvider \Ergebnis\DataProvider\StringProvider::empty()
*/
public function testFromNameRejectsInvalidValueWithAnnotation(string $value): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Value can not be an empty or blank string.');
UserName::fromString($value);
}
// 如果你使用 PHP 8+ 的 Attribute,也可以这样写:
#[Framework\DataProviderExternal(DataProvider\StringProvider::class, 'blank')]
#[Framework\DataProviderExternal(DataProvider\StringProvider::class, 'empty')]
public function testFromNameRejectsInvalidValueWithAttribute(string $value): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Value can not be an empty or blank string.');
UserName::fromString($value);
}
}看到了吗?我们完全移除了
provideInvalidUserNames()
Ergebnis\DataProvider\StringProvider
blank()
empty()
ergebnis/data-provider
Ergebnis\DataProvider\BoolProvider
true
false
arbitrary()
Ergebnis\DataProvider\FloatProvider
arbitrary()
greaterThanOne()
greaterThanZero()
lessThanOne()
lessThanZero()
one()
zero()
Ergebnis\DataProvider\IntProvider
arbitrary()
greaterThanOne()
greaterThanZero()
lessThanOne()
lessThanZero()
one()
zero()
Ergebnis\DataProvider\NullProvider
null
null()
Ergebnis\DataProvider\ObjectProvider
stdClass
object()
Ergebnis\DataProvider\ResourceProvider
resource()
Ergebnis\DataProvider\StringProvider
blank()
empty()
arbitrary()
trimmed()
untrimmed()
withWhitespace()
Ergebnis\DataProvider\UuidProvider
caseLower()
caseUpper()
arbitrary()
这些提供者都设计得非常细致,几乎覆盖了你在单元测试中所有常见的输入场景。
引入
ergebnis/data-provider
ergebnis/data-provider
@dataProvider
#[Framework\DataProviderExternal]
总之,
ergebnis/data-provider
以上就是如何解决PHPUnit测试中数据提供者重复冗余的问题,使用ergebnis/data-provider让你的测试代码更优雅高效的详细内容,更多请关注php中文网其它相关文章!
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号