0

0

如何解决PHPUnit测试中数据提供者重复冗余的问题,使用ergebnis/data-provider让你的测试代码更优雅高效

WBOY

WBOY

发布时间:2025-08-27 13:10:43

|

456人浏览过

|

来源于php中文网

原创

可以通过一下地址学习composer学习地址

作为一名php开发者,我们深知单元测试的重要性。而phpunit作为事实上的标准测试框架,其数据提供者(data provider)功能更是让我们能够用一套测试逻辑覆盖多种输入场景,极大地提高了测试效率。然而,在实际项目中,我却常常被一个问题困扰:为各种常见数据类型(比如空字符串、空白字符串、负数、零、布尔值等)编写数据提供者时,总是不得不一遍又一遍地重复编写相似的代码。

想象一下,你正在测试一个用户注册功能,需要验证用户名不能是空字符串或只包含空格。你可能会写出这样的代码:

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
这个 Composer 包。它就像一道曙光,彻底解决了我在 PHPUnit 测试中数据提供者重复冗余的问题,让我的测试代码变得前所未有的优雅和高效。

ergebnis/data-provider
提供了一系列预定义的、通用的数据提供者,涵盖了 PHP 中最常用的数据类型,例如布尔值、浮点数、整数、null、对象、资源、字符串以及 UUID。这意味着,你不再需要为这些常见类型的数据编写自己的数据提供者,只需简单引用即可。

立即学习PHP免费学习笔记(深入)”;

使用

ergebnis/data-provider
非常简单,首先通过 Composer 安装:

BlackBox AI
BlackBox AI

AI编程助手,智能对话问答助手

下载
composer require ergebnis/data-provider

安装完成后,你就可以在你的 PHPUnit 测试中直接引用它提供的各种数据提供者了。让我们回到之前那个“用户名不能是空字符串或空白字符串”的例子,使用

ergebnis/data-provider
后,代码会变得异常简洁:

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()
    )、大于1(
    greaterThanOne()
    )、大于0(
    greaterThanZero()
    )、小于1(
    lessThanOne()
    )、小于0(
    lessThanZero()
    )、1.0(
    one()
    )、0.0(
    zero()
    )等。
  • Ergebnis\DataProvider\IntProvider
    : 提供任意整数(
    arbitrary()
    )、大于1(
    greaterThanOne()
    )、大于0(
    greaterThanZero()
    )、小于1(
    lessThanOne()
    )、小于0(
    lessThanZero()
    )、1(
    one()
    )、0(
    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()
    )的 UUID 字符串,以及任意大小写(
    arbitrary()
    )。

这些提供者都设计得非常细致,几乎覆盖了你在单元测试中所有常见的输入场景。

引入

ergebnis/data-provider
后,我真切感受到了它的巨大优势:

  1. 告别样板代码:彻底消除了为通用数据类型重复编写数据提供者的烦恼,让我的测试文件更专注于业务逻辑的验证。
  2. 提升可读性:测试方法不再被冗长的数据提供者方法所干扰,一眼就能看出测试的意图。
  3. 增强一致性:所有团队成员都可以使用同一套标准化的数据,确保测试覆盖的全面性和一致性。
  4. 简化维护:如果需要更新某种数据类型(例如,增加一种新的空白字符),只需
    ergebnis/data-provider
    库自身更新,或者我可以在我自己的项目里扩展它,而无需修改大量测试文件。
  5. 提高开发效率:编写测试的速度显著加快,因为大部分基础数据我已经无需自己去构建。
  6. 强大的组合能力:你可以像例子中那样,通过
    @dataProvider
    #[Framework\DataProviderExternal]
    组合多个提供者,轻松构建复杂的测试场景。

总之,

ergebnis/data-provider
是一个非常实用且优雅的 PHPUnit 辅助库。如果你也曾被数据提供者的重复编写所困扰,那么我强烈推荐你尝试一下它。它不仅能让你的测试代码更加精简、易读,还能大幅提升你的开发效率和测试质量。让我们的测试代码,从今天开始,变得更加智能和高效吧!

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
composer是什么插件
composer是什么插件

Composer是一个PHP的依赖管理工具,它可以帮助开发者在PHP项目中管理和安装依赖的库文件。Composer通过一个中央化的存储库来管理所有的依赖库文件,这个存储库包含了各种可用的依赖库的信息和版本信息。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

154

2023.12.25

数据类型有哪几种
数据类型有哪几种

数据类型有整型、浮点型、字符型、字符串型、布尔型、数组、结构体和枚举等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

309

2023.10.31

php数据类型
php数据类型

本专题整合了php数据类型相关内容,阅读专题下面的文章了解更多详细内容。

222

2025.10.31

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

236

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

458

2024.03.01

resource是什么文件
resource是什么文件

Resource文件是一种特殊类型的文件,它通常用于存储应用程序或操作系统中的各种资源信息。它们在应用程序开发中起着关键作用,并在跨平台开发和国际化方面提供支持。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

156

2023.12.20

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

298

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

Golang 网络安全与加密实战
Golang 网络安全与加密实战

本专题系统讲解 Golang 在网络安全与加密技术中的应用,包括对称加密与非对称加密(AES、RSA)、哈希与数字签名、JWT身份认证、SSL/TLS 安全通信、常见网络攻击防范(如SQL注入、XSS、CSRF)及其防护措施。通过实战案例,帮助学习者掌握 如何使用 Go 语言保障网络通信的安全性,保护用户数据与隐私。

2

2026.01.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
第二十四期_PHP8编程
第二十四期_PHP8编程

共86课时 | 3.4万人学习

成为PHP架构师-自制PHP框架
成为PHP架构师-自制PHP框架

共28课时 | 2.5万人学习

第二十三期_PHP编程
第二十三期_PHP编程

共93课时 | 6.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号