0

0

构建可测试主题:单元测试初学者指南

王林

王林

发布时间:2023-09-04 16:29:09

|

1187人浏览过

|

来源于php中文网

原创

在本系列的前两篇文章中,我们从高层次上了解了单元测试是什么以及如何在插件开发环境中应用它。当然,wordpress 不仅仅是编写插件,不是吗? wordpress 开发人员工作的一个重要部分 - 对于某些人来说,这是最重要的部分 - 是主题开发。

因此,在本文中,我们将了解如何开发可测试的主题。具体来说,我们将看看主题与插件有何不同,然后我们将编写一个极其简单的主题,用于演示单元测试的原则并可在未来的开发中应用。


了解主题与插件有何不同

在我们开始创建主题或检查任何代码之前,了解主题和插件开发的区别非常重要。首先,插件可以通过两种方式编写:

  • 作为封装一组函数的对象(这就是我们在本文中所做的)。
  • 作为简单的函数集合

这两种方法都做同样的事情:也就是说,它们使用函数和过滤器的集合来向 WordPress 引入新功能。主要区别在于函数的封装方式。

但是当谈到主题开发时,实际上只有一种方法来开发主题,那就是使用 functions.php 中定义的函数集合。这给编写主题单元测试带来了以下两个挑战:

  • 由于主题不是面向对象的,因此我们无法像上一篇文章中那样将对象实际存储在数组中
  • 我们必须确定一种编写和评估主题功能的方法,这些功能可以独立于将主题加载到浏览器中而运行

因为好的主题使用过滤器和操作的集合,所以我们将创建一个遵循这些最佳实践的主题,并且因为这篇特定文章的重点在于单元测试主题,所以更多的重点将放在编写测试而不是创建一个美观、功能强大的主题。


准备单元测试

在编码之前,让我们初始化我们的项目目录。我们需要设置主题的框架,以便在您的 WordPress 主题目录中为主题创建一个新目录。我的叫做基本主题。添加以下文件(我们稍后会填写):

  • footer.php
  • functions.php
  • header.php
  • index.php
  • style.css

让我们继续删除样式表,以便 WordPress 识别主题并允许我们从仪表板中激活它。为此,请添加以下代码:

/*
Theme Name: Basic Theme
Theme URI: TODO
Version: 1.0
Description: A basic theme used to demonstrate how to write unit tests for themes.
Author: Tom McFarlin
Author URI: https://tommcfarlin.com
License: GNU General Public License v2.0
License URI: http://www.gnu.org/licenses/gpl-2.0.html
*/

为了完整,请继续将 PHP 开始和结束标记添加到函数文件的开头和结尾。这将确保我们在本文后面开始编写主题函数时奠定基础。

并添加一个名为tests的新目录。在这里,我们需要进行 WordPress 测试。


WordPress 测试:简单介绍

在本系列的前面,我提供了位于 GitHub 上的 WordPress 测试的链接。尽管这些测试很好用,但最新的、Automattic 维护的 WordPress 测试位于此 Subversion 存储库中。

如果您是高级开发人员,那么我建议您查看这些测试;但是,如果您刚刚开始进行单元测试 – 没问题!我在 GitHub 存储库中提供了所有源代码(包括 WordPress 测试),您可以下载、引用并将其用于您自己的项目。

安装测试后,您的主题目录应如下所示:

构建可测试主题:单元测试初学者指南

由于 PHPUnit 必须从命令行执行,因此您需要打开终端会话(或命令提示符),导航到 tests 目录,然后您应该能够运行它们使用以下命令(作为示例):

phpunit tests/test_user_capabilities.php

你的终端应该输出如下内容:

构建可测试主题:单元测试初学者指南

注意:如果您无法执行测试,请参阅本系列的第一篇文章来验证您的配置。此外,您的里程可能会根据您的操作系统、网络服务器和本地计算机配置而有​​所不同。如果您最终不得不做一些不同的事情,请在评论中分享您的笔记以帮助其他人。

基本主题:可单元测试的 WordPress 主题

此时,让我们继续激活仪表板中的主题。主题应该激活(如果没有激活,请确保模板文件中没有任何杂散字符)。如果您尝试查看主题,它自然会显示白屏。

在编写任何测试之前,让我们继续使用一些内容填充我们的模板文件,以便我们可以在前端显示一些内容。

header.php中,添加以下代码:

<!DOCTYPE html>
<html>
	<head>	
		<meta charset="UTF-8">
		<link rel="profile" href="http://gmpg.org/xfn/11" />
		<link rel="pingback" href="<?php bloginfo( 'pingback_url' ); ?>" />
		<title><?php wp_title( '' ); ?></title>
		<?php wp_head(); ?>
	</head>
	<body <?php body_class(); ?>>
	
		<div id="header">
			This is the header.
		</div><!-- /#header -->

index.php中,添加以下代码:

<?php get_header(); ?>

	<div id="content">
		This is the content.
	</div><!-- /#content -->

<?php get_footer(); ?>

并在footer.php中添加以下代码:

		<div id="footer">
			This is the footer.
		</div><!-- /#footer -->

	</body>
</html>

很简单,我知道,但这足以让我们在开始编写测试时使用。保存您的工作,在浏览器中查看主题,您应该会看到以下内容:

构建可测试主题:单元测试初学者指南


编写单元测试

测试主题激活

在您的 tests 目录中,创建一个名为 test_basic_theme.php 的文件,并对该文件进行存根处理,如下所示:

// Include the functions for the theme
include_once('../functions.php');

class Test_Basic_Theme extends WP_UnitTestCase {
	
} // end class

上面,我们定义了一个类,用于包装所有主题的单元测试。

首先,我们定义 setUp 方法。 setUp 方法是 WordPress 测试框架提供的函数,我们可以使用它在测试运行之前触发某些函数。例如,当 WordPress 测试运行时,它们会针对默认主题(即“211”)运行。在我们的例子中,我们希望针对我们自己的主题运行测试。

Insou AI
Insou AI

Insou AI 是一款强大的人工智能助手,旨在帮助你轻松创建引人入胜的内容和令人印象深刻的演示。

下载

为此,我们需要告诉 WordPress 在运行其余测试之前实际切换主题。由于这需要在测试运行之前发生,因此需要在 setUp 方法中定义。有道理吗?

所以让我们编写 setUp 方法:

function setUp() {
	
	parent::setUp();
	switch_theme( 'Basic Theme', 'Basic Theme' );
	
} // end setup

再次执行我们的测试。我们可以通过运行与最初设置测试时相同的命令来完成此操作:

phpunit tests/test_basic_theme.php

如果您已正确完成所有操作,那么在测试运行时您实际上应该会看到失败:

构建可测试主题:单元测试初学者指南

但错误消息很明确:“在类“Test_Basic_Theme””中找不到测试。因此,让我们减轻这种情况并为主题编写第一个测试。它可以是非常简单的事情,但请记住上一篇文章中我们不想只测试最佳路径,而是还要测试失败路径。

因此,我们需要测试基本主题是否处于活动状态以及“211”是否处于活动状态。为此,我们将使用assertTrue 方法和assertFalse 方法,并且我们将在两个函数的上下文中执行此操作。查看下面的代码并相应地更新您的测试文件:

function testActiveTheme() {

	$this->assertTrue( 'Basic Theme' == get_current_theme() );
	
} // end testThemeInitialization

function testInactiveTheme() {

	$this->assertFalse( 'Twenty Eleven' == get_current_theme() );

} // end testInactiveTheme

再次执行测试,您应该看到它们运行绿色。不错,对吧?

构建可测试主题:单元测试初学者指南

这是一个相对简单的功能,因此让我们考虑一下我们的主题可以具有的一些高级功能。

测试 jQuery 是否已入队

开箱即用的基本主题不包含 jQuery,因此我们将其包含在我们的主题中。如果您还记得之前的帖子,正确的单元测试方法如下:

  1. 编写测试
  2. 运行测试(它会失败)
  3. 编写使测试通过所需的代码
  4. 运行测试(它应该通过,允许第 3 步正确完成)

那么,让我们对 jQuery 执行此操作。

首先,我们需要编写一个测试来确定 jQuery 是否已加载。我们将使用 WordPress 函数 wp_script_is。由于主题在浏览器中经历正常的页面生命周期,因此我们需要使用 do_action 函数手动告诉 WordPress 加载 jQuery。

function testjQueryIsLoaded() {

	$this->assertFalse( wp_script_is( 'jquery' ) );

	do_action( 'wp_enqueue_scripts' );
	$this->assertTrue( wp_script_is( 'jquery' ) );

} // end testjQueryIsLoaded

在我们进一步讨论之前,这里有一些重要的事情需要注意:我不喜欢在一个函数中放置多个断言,因为我认为每个函数应该用于测试一个目的;然而,也有例外。在这里,我们需要确保在调用 do_action 之前未加载 jQuery。

无论如何,运行测试都会失败。因此,我们需要将代码添加到 functions.php 中,以确保将 jQuery 添加到我们的主题中。为此,请在函数文件中包含以下函数:

function basic_add_jquery() {

	wp_enqueue_script( 'jquery' );	
	
} // end basic_remove_jquery
add_action( 'wp_enqueue_scripts', 'basic_add_jquery' );

最后,运行测试,它应该是绿色的。很简单,不是吗?

测试元描述

假设我们想要在主页上包含默认元描述。在最简单的情况下,它只不过是博客的描述。因此,按照上面概述的方法,我们引入一个函数来测试添加到 head 元素的元描述字符串是否符合我们的预期:

function testBasicMetaDescription() {
	
	$meta_description = '<meta name="description" content="' . get_bloginfo( 'description' ) . '" />';
	$this->expectOutputString( $meta_description, basic_meta_description() );
	
} // end testBasicMetaDescription

运行它——它会失败。请注意,我没有使用标准 assertTrueassertFalse 函数 - 稍后会有更多详细信息。现在,我们将以下函数引入到functions.php中:

function basic_meta_description() {
	
	echo '<meta name="description" content="' . get_bloginfo( 'description' ) . '" />';
	
} // end basic_meta_description
add_action( 'wp_head', 'basic_meta_description' );

请注意,此函数挂钩到 wp_head 操作。为了将元描述写入 head 元素,我们必须回显字符串,而不是返回字符串。

现在,请注意,在上面的测试中,我们使用的是 expectOutputString。当我们需要评估一个回显一个字符串(而不是返回一个字符串)的函数时,这非常有用。由于 wp_head 操作将返回大量数据(即整个 head 元素),因此我们实际上只需要评估返回的元描述。这就是为什么我不调用 do_action( 'wp_head' ) ,而是简单地调用函数本身并根据我期望的结果评估输出。

再次运行 PHPUnit,您的测试应该全部通过。


测试所有事情

显然,我们只是触及了单元测试对主题开发的表面作用。还有很多东西可以测试 - 我们甚至还没有考虑过测试 The Loop、评估帖子格式的各种方法,甚至还没有考虑如何检查评论。

请记住,这是一本初学者指南,这三篇文章涵盖了很多内容。

无论如何,原则是相同的:问题是确保以编程方式触发适当的函数或操作,并在预期和意外情况下评估其输出。

最后,您可以在此 GitHub 存储库中找到整个项目以及记录的函数。


资源

以下是本文中使用的资源的摘要:

  • 什么是单元测试?
  • 构建可测试的插件
  • PHPUnit
  • 官方 WordPress 测试
  • assertTrue
  • assertFalse
  • wp_script_is
  • do_action
  • wp_head
  • expectOutputString
  • GitHub 上的基本主题

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

热门AI工具

更多
DeepSeek
DeepSeek

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

豆包大模型
豆包大模型

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

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

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

文心一言
文心一言

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

讯飞写作
讯飞写作

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

即梦AI
即梦AI

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

ChatGPT
ChatGPT

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

相关专题

更多
TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

49

2026.03.13

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

89

2026.03.12

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

276

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

59

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

99

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

105

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

230

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

619

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

173

2026.03.04

热门下载

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

精品课程

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

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