在本系列的前两篇文章中,我们从高层次上了解了单元测试是什么以及如何在插件开发环境中应用它。当然,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”)运行。在我们的例子中,我们希望针对我们自己的主题运行测试。
为此,我们需要告诉 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,因此我们将其包含在我们的主题中。如果您还记得之前的帖子,正确的单元测试方法如下:
- 编写测试
- 运行测试(它会失败)
- 编写使测试通过所需的代码
- 运行测试(它应该通过,允许第 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
运行它——它会失败。请注意,我没有使用标准 assertTrue
、assertFalse
函数 – 稍后会有更多详细信息。现在,我们将以下函数引入到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 上的基本主题
以上就是构建可测试主题:单元测试初学者指南的详细内容,更多请关注php中文网其它相关文章!