讲师中心 微信公众号
AI工具推荐 视频效率加速

写PHP代码您搞过单元测试吗

梦伟小哥_3440

梦伟小哥_3440

发布时间:2016-06-13 12:19:01

|

1183人浏览过

|

来源于php中文网

原创

写PHP代码你搞过单元测试吗

其实一开始我内心是想做单元测试(unit testing)的,但时间久了,也就不想了。

要想通过PHP编程成为技术领域的专家,其实功夫在PHP之外。数据库至少得看几本书,xml至少得看一本书,单元测试至少得看一本书,软件工程至少看一本,数据结构与算法至少看一本,*nix至少得看一本,Web服务器至少看一本,佛经得看一本,道德经得看一本,易经可能也得看一本,等等,不停的看下去。

概念

要写单元测试,必须要有一些基本概念。这些概念PHP是不会教给你的。

我们先从百度百科中吸取一点营养。

工厂在组装一台电视机之前,会对每个元件都进行测试,这就是单元测试。

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

单元测试,是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。总的来说,单元就是人为规定的最小的被测功能模块。单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。

单元测试是由程序员自己来完成,最终受益的也是程序员自己。程序员有责任编写功能代码,同时也就有责任为自己的代码编写单元测试。执行单元测试,就是为了证明这段代码的行为和我们期望的一致。

--百度百科

安装

PHPUnit目前稳定版已到了4.6,网上很多的姿势都已失效。比如,发行方式,以前都是用Pear进行安装,现在呢,直接是Phar包或者Composer的方式依赖安装。

wget https://phar.phpunit.de/phpunit.phar? chmod +x phpunit.phar? sudo mv phpunit.phar /usr/local/bin/phpunit? phpunit --version
{    "require-dev": {        "phpunit/phpunit": "4.6.*"    }}

但另一个对初学者很关键的东东phpunit-skelgen就没有包含在这个包里,而且很难找到下载地址:https://phar.phpunit.de/phpunit-skelgen.phar

wget https://phar.phpunit.de/phpunit-skelgen.pharchmod +x phpunit-skelgen.pharmv phpunit-skelgen.phar /usr/local/bin/phpunit-skelgen

解决的问题

在开发过程中,当需要对软件的内部结构进行更改时,你实际上是要在不影响其可见行为的情况下让它更加容易理解、更加易于修改,测试套件对于安全地进行这些所谓的重构而言是非常宝贵的。否则,你可能在重组过程中将系统搞坏而不自知。

在使用单元测试来确认重构的转换步骤中确实保持原有行为并且没有引入错误时,以下情况有助于改进项目的编码与设计:

  • 所有单元测试均正确运行。

  • 代码传达其设计原则。

  • 代码没有冗余。

  • 代码所包含的类和方法的数量降至最低。

当需要向系统内添加新的功能时,首先为其编写测试。然后,当测试能够正常运行就标志着开发完成了。

优点

1、它是一种验证行为。

程序中的每一项功能都是测试来验证它的正确性。它为以后的开发提供支援。就算是开发后期,我们也可以轻松的增加功能或更改程序结构,而不用担心这个过程中会破坏重要的东西。而且它为代码的重构提供了保障。这样,我们就可以更自由的对程序进行改进。

2、它是一种设计行为。

编写单元测试将使我们从调用者观察、思考。特别是先写测试(test-first),迫使我们把程序设计成易于调用和可测试的,即迫使我们解除软件中的耦合。

3、它是一种编写文档的行为。

单元测试是一种无价的文档,它是展示函数或类如何使用的最佳文档。这份文档是可编译、可运行的,并且它保持最新,永远与代码同步。

4、它具有回归性。

自动化的单元测试避免了代码出现回归,编写完成之后,可以随时随地的快速运行测试。

实践

什么时候测试?

单元测试越早越好,早到什么程度?

极限编程(Extreme Programming,或简称XP)讲究TDD,即测试驱动开发,先编写测试代码,再进行开发。在实际的工作中,可以不必过分强调先什么后什么,重要的是高效和感觉舒适。

从经验来看,先编写产品函数的框架,然后编写测试函数,针对产品函数的功能编写测试用例,然后编写产品函数的代码,每写一个功能点都运行测试,随时补充测试用例。

所谓先编写产品函数的框架,是指先编写函数空的实现,有返回值的直接返回一个合适值,编译通过后再编写测试代码,这时,函数名、参数表、返回类型都应该确定下来了,所编写的测试代码以后需修改的可能性比较小。

由谁测试?

单元测试与其他测试不同,单元测试可看作是编码工作的一部分,应该由程序员完成,也就是说,经过了单元测试的代码才是已完成的代码,提交产品代码时也要同时提交测试代码。测试部门可以作一定程度的审核。

请一定要看完官方文档:。

要进行充分的单元测试,一般来说应专门编写测试代码,并与产品代码隔离。但对于初学者来说,总是会有点别扭,因为感觉额外做了很多工作,影响开发效率。其实像phpunit也是支持在类方法的文档注释块(docblock)中使用 @test 标注将其标记为测试方法的。这样,彻底贯彻我们代码即文档的思想。

<?phpclass Calculator{    /**     * @assert (0, 0) == 0     * @assert (0, 1) == 1     * @assert (1, 0) == 1     * @assert (1, 1) == 2     * @assert (1, 2) == 4     */    public function add($a, $b)    {        return $a + $b;    }}

现实难题

我们到底要测什么?算法?一般很少。

大都是在编写业务功能。而且大多数是基于数据库的系统开发。这是我们实施PHP单元测试最大的难点所在。需要整合PHPUnit的DBUnit测试,也就是一开始就得学习DBUnit的知识。

在各种编程语言中,许多入门与中级的单元测试范例都暗示着这样一种信息:很容易用简单的测试来对应用程序的逻辑进行测试。但是对于以数据库为中心的应用程序而言,这与现实相去甚远。一旦开始使用诸如 Wordpress、TYPO3、或 Symfony(配合 Doctrine 或 Propel)之类的东西,就很容易在用 PHPUnit 时碰到超多问题:正是由于这些库和数据库之间实在耦合的太紧密了。

你大概会在日常工作面对的项目中经历这一幕。你打算把你那或生疏或纯熟的 PHPUnit 技能用到工作中去,结果被以下问题之一卡住了:

  • 待测方法执行了一个相当大的 JOIN 操作,并且得到的数据用于计算某些重要的结果。
  • 业务逻辑中混合执行了 SELECT、INSERT、UPDATE 和 DELETE 语句。
  • 为了给待测方法建立合理的初始数据,需要在两个以上(可能远超过)表里设置测试数据。

DbUnit

DbUnit扩展大大简化了为测试设置数据库的操作,并且可以在对数据执行了一系列操作之后验证数据库的内容。

DbUnit所支持的供应商

DbUnit 目前支持 MySQL、PostgreSQL、Oracle 和 SQLite。通过集成 Zend Framework 或 Doctrine 2,也可以访问其他数据库系统,比如 IBM DB2 或者 Microsoft SQL Server。

数据库测试的难点

为什么所有单元测试的范例都不包含数据库交互?这里有个很好的理由:这类测试的建立和维护都很复杂。对数据库进行测试时,需要考虑以下这些变数:

  • 数据库和表
  • 向表中插入测试所需要的行
  • 测试运行完毕后验证数据库的状态
  • 每个新测试都要清理数据库

许多数据库 API,比如 PDO、MySQLi 或者 OCI8,都十分繁琐且书写起来十分冗长,因此,手工进行这些步骤绝对是噩梦。

测试代码应当尽可能简短精确,这有若干原因:

  • 你不希望因为生产代码的小变更而需要对测试代码进行数量可观的修改。

  • 你希望在哪怕好几个月以后也能轻松地阅读并理解测试代码。

另外,必须认识到,对于代码而言,本质上来说数据库是全局输入变量。测试套件中的两个不同的测试可能是运行在同一个数据库上的,并且可能把数据重用好多次。一个测试中出现的失败很容易影响到后继测试的结果,从而让整个测试过程变得非常艰难。前面提到的清理步骤对于解决“数据库是全局输入”的问题是非常重要的。

DbUnit 以一种优雅的方式来帮助简化数据库测试中的所有这些问题。

PHPUnit 无法帮你解决的问题是,相对于不使用数据的测试而言,数据库测试是非常慢的。随着数据库交互规模的增大,运行测试可能需要耗费可观的时间。然而,只要保持每个测试所使用的数据量较小并且尽可能用非数据库测试来对代码进行测试,即使很大的测试套件也能轻松在一分钟内跑完。

数据库测试的四个阶段

Gerard Meszaros 在他的书《xUnit 测试模式》中列出了单元测试的四个阶段:

  • 建立基架(fixture)
  • 执行被测系统
  • 验证结果
  • 拆除基架(fixture)

什么是基架(fixture)?

基架(fixture)是对开始执行某个测试时应用程序和数据库所处初始状态的描述。

对数据库进行测试至少要处理建立与拆除的步骤,在其中完成清理工作,并将所需的基架数据写入表内。然而对于数据库扩展模块而言,在数据库测试中有很好的理由将这四个步骤还原成类似下面这样的工作流程,这个流程对于每个测试都会完整执行:

  1. 清理数据库

由于总是会有某个测试运行在并不确定表中是否有数据的数据库上,PHPUnit 在所有指定表上执行 TRUNCATE 操作来把它们清空。

  1. 建立基架

PHPUnit 随后将迭代所有指定的基架数据行并将其插入到对应的表里。

3–5. 运行测试、验证结果、并拆除基架

在所有数据库都完成重置并加载好初始状态后,PHPUnit 才会执行实际的测试。这个部分的测试代码完全不需要数据库扩展模块的参与,可以随意测试任何想要测试的内容。

在测试中,验证的目的可以使用一个名为 assertDataSetsEqual() 的特殊断言来实现。当然,这完全是可选的。

一些术语

  • 单元测试
  • 集成测试
  • 回归测试
  • 测试用例
  • 断言
  • 基架Fixture

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

火山引擎

火山引擎是一款面向企业的云计算与AI服务平台。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

Lovart
Lovart Hot

一款面向视觉设计创作的AI设计平台,可通过智能体和画布工作流辅助制作海报、Logo、网页、PPT及其他视觉内容。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

相关专题

更多
PixTV官网入口地址合集
PixTV官网入口地址合集

本专题汇总了 PixTV AI 一站式视频创作平台的官方入口与使用教程。无需下载软件,浏览器直接访问即可使用。平台将剧本、图像、视频、声音与剪辑整合在“无限画布”中,接入 GPT Image 2.5、Seedance 2.5 等头部模型。本专题整理了从新建画布、角色锚定、分镜拆分到视频生成与导出的完整操作指南,助你快速上手 AI 短剧与漫剧创作。

20

2026.10.10

Kratos框架HTTP与gRPC服务开发教程
Kratos框架HTTP与gRPC服务开发教程

本专题围绕Kratos框架双协议服务开发,涵盖HTTP路由与处理器编写、参数获取、gRPC服务实现与客户端调用、metadata上下文传递、encoding编解码注册、统一响应封装、超时控制与流式响应实现方法。

20

2026.10.10

Kratos框架Protobuf接口定义与代码生成合集
Kratos框架Protobuf接口定义与代码生成合集

本专题讲解Kratos框架接口定义体系,涵盖proto编写规范、proto add/client/server生成命令、http注解路由、validate校验、OpenAPI文档生成、跨服务proto复用与兼容性设计。

0

2026.10.10

C++虚函数怎么定义和调用
C++虚函数怎么定义和调用

C++虚函数是实现运行时多态的重要机制。本专题从virtual关键字的基本用法入手,介绍基类与派生类之间的函数重写、基类指针调用派生类方法,以及动态绑定的执行过程,帮助初学者掌握虚函数的核心语法。

20

2026.10.10

C++类与对象的封装方法教程
C++类与对象的封装方法教程

C++封装是面向对象编程的核心特性之一,通过类将数据与操作数据的函数组织在一起,并利用访问权限控制外部访问。本专题介绍类的定义、成员变量、成员函数以及public、private和protected的使用方法,帮助初学者掌握封装的基本原理。

20

2026.10.10

C++构造函数定义与调用方法
C++构造函数定义与调用方法

C++构造函数用于初始化类对象,是面向对象编程的重要基础。本专题从构造函数的定义、声明和调用入手,介绍默认构造函数、带参数构造函数、拷贝构造函数及成员初始化列表,帮助初学者掌握对象创建与初始化的基本方法。

20

2026.10.10

Kratos框架零基础入门教程
Kratos框架零基础入门教程

本专题整理Kratos框架入门内容,涵盖Go环境准备、kratos CLI安装升级、new命令创建项目、目录结构分层说明、服务启动与双协议端口、依赖下载报错排查,帮助开发者快速跑通第一个Kratos框架微服务应用。

20

2026.10.10

C++条件判断语句怎么写
C++条件判断语句怎么写

C++条件判断是控制程序执行流程的重要基础。本专题介绍if、if-else、else if和switch等常见分支语句,结合条件表达式、比较运算符与代码示例,帮助初学者掌握不同场景下的判断逻辑。

0

2026.10.10

C++变量怎么声明和赋值
C++变量怎么声明和赋值

C++变量是编写程序和存储数据的基础。本专题围绕变量声明、定义、初始化、赋值和类型选择等内容展开,帮助初学者理解不同变量的用法,并掌握在实际代码中定义和使用变量的方法。

20

2026.10.10

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Composer 从入门到实战
Composer 从入门到实战

共1课时 | 177人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn