SimpleTest

原文链接http://drupal.org/simpletest.

SimpleTest是Drupal的定制性测试框架。SimpleTest已经成为Drual7开发周期中必不可少的工作流的一部分,它已作为测试模块并入内核。它极大程度地增强了内核的开发、使对重大API的改进得到可能,并信心倍增。在Drupal6中,它称为SimpleTest模块,存在contributed仓储中。

chx称: "Drupal 7" 内核已经比以前任何一个版本稳定的多了”.

有了这个测试框架让Drupal7增色不少。

Drupal7 内核测试 通常采用下面三种方法中的一种:
• 功能性测试(Function test)是最常用的。该方法安装一个新的数据库,在数据库中先产生专用测试数据,再按预期的结果来推测。
• 单元测试(Unit Tests)方法不需要在后台进行数据库安装。该方法对于单个功能模块的测试很有用,不需要考虑大的系统开发的情况。
• 升级测试(Upgraded Tests)方法是导出老版本的数据库,再通过运行update.php导入后进行测试。

SimpleTest 概述

原文链接http://drupal.org/node/394888

测试方法

Drupal测试更关注于功能测试(functional testing)而不是单元(unit testing)测试。也就是说,测试是对接口整体进行的,而不是针对个别模块功能或几段代码的测试。Drupal关注功能测试因为这样可以使Drupal开发更为有效。它至少和单元测试一样有效。测试框架是以功能测试为导向的,本小结重点讲述如何进行功能测试。

建立独立的测试环境

测试框架会自动为每次测试实例产生一个独立的测试环境。即每次会创建一个独立的文件夹目录和一套完全独立的数据库表格。Drupal安装在该环境中进行测试。这样保证了每次测试都是干净的环境,不可能和其他测试混淆。开发者也不需要每次测试后清理环境。
建立独立的测试环境是必要的,它保证了每次测试实例都是初始化的。还有在本地开发环境中做的任何改变都不会带入到该测试环境中。每个测试都要经过必要的安装配置(如:创建内容、用户等)

测试实例布局

每一个测试实例只能用一个setup()和一个tearDown()来实现。这就是说需要启用相同模块组及测试相同功能的所有测试要归并到一个测试组中。不同安装的测试实例要分开,但是都保存在同一个测试文件中。

测试文件位置

对一个模块的所有测试应该统一存放到该模块目录下的测试文件中。文件名格式为modulename.test。比如:节点模块的测试文件为: modules/node/node.test。如果像测试模块需要其他测试文件,要放到测试目录下,则该测试目录也应该放到该模块的目录下。

运行测试

测试系统提供了两种运行方法:web接口方法和命令行脚本方法。Web接口可以在站点构建(site building)菜单下的admin/build/testing中找到((Drupal6版本)。或者配置菜单(configuration)下的admin/config/development/test下( Drupal7 版本)。勾选需要测试的选项,然后点击运行按钮。 在页面下方会有一个进度条来显示完成的百分比和运行情况。
如果要用命令行脚本形式,则在scripts目录下有个名叫run-test.sh的脚本。详细的方法可以参加相关文档,或者在console上直接运行./scripts/run-test.sh.

 

SimpleTest 和测试模块

原文链接http://drupal.org/documentation/modules/simpletest

SimpleTest模块(Druapl6.x)或测试模块(Drupal7.x及更高版本)提供了一个在drupal 中自动进行单元和功能测试的框架。它可以用来验证代码更改前后的状态,或为开发者提供了一套编写和测试模块的方法。初始模块是基于SimpleTest PHP library的。
测试列表可以在(drupal 6.x版本)管理(Administer) >>站点建设( Site building) >> SimpleTest下 或在(Drupal7.x) 管理(Administration) >>配置( Configuration) >>开发( Development) >>测试( Testing)下找到。要进行全面测试就选择全部的测试选项,或单独选测试项以进行更有针对性地测试。(注意:全面测试可能要花上好几分钟时间,选则的测试项太多,也可能无法完成测试)。
测试完成后,在每个测试组边上会有消息条显示测试是否通过、失败、或有异常。通过(pass)表示测试返回了预期结果,失败(fail)表示没有返回预期结果。异常则说明有测试以外的错误,比如PHP警告或报警。当失败或异常结果发生时,结果内容会扩展开来显示,通常以红色或粉色行显示。(开发者)可以根据测试结果来优化代码、再此进行测试直到通过。
更多有关创建和修改测试的信息,请参阅drupal手册中其他SimpleTest 文档

SimpleTest 使用指南(Drupal7)

原文链接http://drupal.org/simpletest-tutorial-drupal7

注:本指南中引用代码来自Examples for Developers module,你可以:

  • 从该模块中复制一份代码,编辑、修改然后进行测试.
  • 报告所发现问题,进行修复,欢迎进行补丁修正和提出改进意见。

通过本指南,可以让你掌握基本的测试方法。学习本节后你可以建立第一个测试!在本例中,我们将创建一个叫“simplest example”的dummy 模块,它提供一个叫”simplest_example” 的内容类型。 这个内容类型和任何基本drupal节点类型(如:’page’)一样。本指南将阐述如何对这个simplest_example内容类型进行测试,从而保证其功能的有效实现。

准备工作

首先,我们要确保simpletest模块已安装。在Drupal7中,simpletest已是内核的一部分称为测试模块。如果你还没有安装该模块,确保Simpletest模块已经启用。

在Drupal7中,Simpletest Verbose选项默认是打开的。当然如果想确保它是否是打开的,,则可以去管理/配置/开发/设置(admin/config/development/testing/settings)下检查。

本指南所采用的例子取自http://drupal.org/project/examples

Drupal Simpletest如何工作

大多数Drupal功能是面向web的,因此演习这些功能是及其重要的。Simpletest生成一份完整的安装和一个虚拟的web浏览器,通过这个虚拟浏览器来进行一系列测试,就如你手工一步步进行一样。记住每次测试都是在运行一个完整的新的durpal实例是非常重要的。换而言之,每一个测试实例是空的,没有进行过任何配置,建立过任何用户,除了默认的内核模块,其他模块都未开启。如果你的测试需要一个有特权的用户,你就需要创建一个(这如同你手工创建一个测试环境一样)。如果有需要的模块,你就需要开启他们。如果需要配置,就要用simpletest来进行配置,因为在我们要测试的druapl实例中,该测试站点还未进行过任何配置,文件目录下也没有任何文件,也未安装过可选模块,也没有创建过任何用户。在simpletest中,我们有神奇的命令去执行它们,稍后我们会做进一步讲解。

关于Simpletest Example模块

Simpletest Example模块给出了一个可配置的节点类型(如’page’或者’story’).该类型有一个标题和一个正文组成。借此它给我们演示了测试内容创建的机会。为了实现这个节点,我们需要用hook_node_info()钩子函数来创建节点类型,用hook_form()函数来创建表单。我们需要为模块设置权限(为此你需要” create simpletest_example content”权限来创建,或者由”edit own simpletest_example content”取得编剧权限)。当然,我们需要准备一个simpletest_example.info文件。

注意,我们的模块中有一个bug:它的权限处理是有问题的。因此即使给予了’edit own simpletest_example’ 的字符串,simpletest_example_access()函数也不能正确处理,所以当我们赋予用户编辑节点权限室,实际上是不能实现的。当然,手工测试时可能一直用用户1来测试,不会看到测试失败的情况,我们稍后会提到。

本代码在Examples for Developers模块中维护,它有助于在正式发布前,用dummy代码来进行测试、编辑和实践,.建议开发者取些模块,启用并练习。

思考何时需要测试

如果已经安装了simpletest_example模块,你可以按如下步骤一步步来进行,并思考何时需要测试。

访问内容->增加新内容->Simpletest Example 节点类型(Content > Add new content > Simpletest Example Node Type ),你会看到如下页面。

查看界面并选定要测试的内容。

仔细浏览确保你已经熟知接口间是如何工作的,在一个基本实例,而不是Simpletest操作中,功能可以实现。如果你还没有理解原理,是不能写好测试代码的。在本例中,我们来填上标题和正文内容,然后按保存按钮。你将看到如下页面。

 对simpletest_example构建测试

好,我们可以来测试了,我们会在simpletest_example.test文件中操作。(该文件可从下载的模块中获得)

在drupal7中,如果对一个模块添加了一个新的.test文件,则需要在该模块的.info文件将它添加到files[]部分。在我们的例子中,simpletest_example.info文件中在files[]下,就有simpletest_example.test 的记录.

files[] = simpletest_example.test

如果.file文件添加在现有的模块中,则可能需要重刷cache,让drupal知道有新文件产生了。要刷新cache,可以去admin/config/development/performance下点击“clear all chaches”按钮。

进行一个测试需要如下四个步骤:

  • 创建结构(即产生一个从DrupalWebTestCase继承的类)
  • 对任何用户创建或需要的配置的测试实例初始化
  • 用测试实例产生真实测试
  • 当然,要特别想清楚为什么我们的测试没有按预想地进行并调试测试(也许还有模块).

在开始前,我们需要模块扩展DrupalWebTestCase.

<?php
/**
* Tests the functionality of the Simpletest example content type.
*/
class SimpletestExampleTestCase extends DrupalWebTestCase {
  protected
$privileged_user;

}
?>

为了使Simpletest接口调用测试,我们来用getInfo()函数实现。它提供了用户接口信息,并在刷新缓存后,显示在simpletest页面上。

下面就是非常重要的setup()函数了。这里我们就要处理必须处理的,让该Drupal实例按我们的想法工作。我们必须考虑:“我们如何操作,才能从初始化安装到可以在哪里运行测试?在我们的实例中,我们知道必须:

  • 启用Simletest Exmaple模块
  • 创建一个有权限的用户,来产生一个simpletest_example 节点
  • 用该用户登陆

以上工作就是有setup()方法来实现的.

<?php
 
public function setUp() {
   
// Enable any modules required for the test
   
parent::setUp('simpletest_example');
   
// Create and log in our privileged user.
   
$this->privileged_user = $this->drupalCreateUser(array(
     
'create simpletest_example content',
     
'extra special edit any simpletest_example',
      ));
   
$this->drupalLogin($this->privileged_user);
  }
?>

注:在drupal6中,我们必须启用所有关联模块。Drupal7会自动启用有关联的模块.

测试建立:创建节点

现在让我们来创建测试实例练习模块。刚才我们已经为我们的测试类建立了成员函数,每一个成员我们会来练习一个测试。

我们的第一个测试将通过node/add/simpletest-example中的form来创建一个新的simpletest_example节点.

<?php
 
/**
    * Tests creation of a Simpletest example node.
    */
 
public function testSimpleTestExampleCreate() {
   
// Create node to edit.   
   
$edit = array();
   
$edit['title'] = $this->randomName(8);
   
$edit["body[und][0][value]"] = $this->randomName(16);
   
$this->drupalPost('node/add/simpletest-example', $edit, t('Save'));
   
$this->assertText(t('Simpletest Example Node Type @title has been created.', array('@title' => $edit['title'])));
  }
?>

drupalPost, drupalGet和判断语句

以上代码在node/add/simpletest-example页面完成了一个简单的递交表单的功能。它将字段定义到了一个数列中($edit数组产生随机值赋给title和body),然后递交表单,并声明在页面上找到了合适的文本.

大多数的测试将按如下形式来进行:

  • 调用drupalGet()函数来跳转到一个页面或者用drupalPost()来递交表单
  • 用一次或多次语句来检查内容是所见即所得的.

$this->drupalGet($path)可以非常容易的跳到指定页面

$this->drupalPost($path, $edit_fields, $submit_button_name)稍复杂些

还有几十种这样的语句。最容易的一个是$this->assertText($text_to_find_on_page).当超越本指南知识后,你会想参阅更多的语句

测试中的用户和内核环境

测试运行在一个独立的(沙盒)环境中。在测试环境中,用$this->drupalLogin($account)来指定一个用户登陆。像drupalGet和drupalPost的测试方法经常在沙盒中用到。如果要调用内核API函数(如:user_access), 强烈建议将这个测试用户授权于内核环境中。

<?php
$account
= $this->drupalCreateUser(array('access content'));
$this->drupalLogin($account);
global
$user;
$user = user_load($account->uid);
$this->assertFalse(user_access('access content'));
?>

在测试中,Simpletest将用户转换成uid 1,并负责恢复用户,因此我们可以切换用户而不必考虑安全因素。

通过Web界面运行Simpletest

下面我们来运行测试。这里我们将用web界面来运行。

在模块页面,找到你创建的模块,然后进入配置页面。在打开的页面,你会看到有两个标签:配置(Settings)和列表(List)。在列表标签下,你会看到可选择的测试列表。选择你要创建的测试-它会归入”Examples”组—点击并运行”Runtests”(有时可能需要清除Drupal缓存才能在列表中见到)

测试运行后你就能见到是否通过(pass)的结果。

你也可以通过命令行运行。更多的内容请参阅通过命令行来运行测试

一个失败测试的演示

测试成功的例子没有必要多讲了,现在我们来举一个失败的例子。

还是用相同的类,这次来测试编辑节点的情况。我们的模块有一个缺陷-它不能很好的处理”edit own simpletest_exple”权限,当用户仅有此权限时缺不能编辑它。在本实例中我们将创建一个节点,然后来进行编辑。

运行测试并查看结果。

<?php
 
/**
    * Tests editing a Simpletest example node.
    */
 
public function testSimpleTestExampleEdit() {
   
$settings = array(
     
'type' => 'simpletest_example',
     
'title' => $this->randomName(32),
     
'body' => array(LANGUAGE_NONE => array(array($this->randomName(64)))),
    );
   
$node = $this->drupalCreateNode($settings);

   
// For debugging, we might output the node structure with $this->verbose()
   
$this->verbose('Node created: ' . var_export($node, TRUE));
   
// It would only be output if the testing settings had 'verbose' set.

    // We'll run this test normally, but not on the testbot, as it would
    // indicate that the examples module was failing tests.
   
if (!$this->runningOnTestbot()) {
     
// The debug() statement will output information into the test results.
      // It can also be used in Drupal 7 anywhere in code and will come out
      // as a drupal_set_message().
     
debug('We are not running on the PIFR testing server, so will go ahead and catch the failure.');
     
$this->drupalGet("node/{$node->nid}/edit");
     
// Make sure we don't get a 401 unauthorized response:
     
$this->assertResponse(200, t('User is allowed to edit the content.'));

     
// Looking for title text in the page to determine whether we were
      // successful opening edit form. Note that the output message
      //  "Found title in edit form" is not translated with t().
     
$this->assertText(t("@title", array('@title' => $settings['title'])), "Found title in edit form");
    }
  }
?>

单元测试

Simpletest也提供了DrupalUnitTestCase,来作为DrupalWebTestCase的可选类.

单元测试不会产生数据库表格和文件目录. 所以单元测试要比功能测试初始化快,但这也意味着它不能访问数据库和文件目录。调用任何一个需要数据库看函数会产生异常。这些函数包括routine 函数,比如watchdog(), module_implements(), module_invoke_all() 等。

更多的编写单元测试的资料请参阅用Simpletest来进行单元测试

何时在Simpletest中用t()函数

和Drupal中的大多数字符串不同,simpletest的字符串不经常用到t()函数。这里有两个原因:

  1. 许多simpletest的字符串仅仅是测试目的,不会用到网站上,因此不需要解释它们。
  2. 当不同组件尽可能分开时,它能比较容易地提供永久、强大的覆盖面.(即:不需要时的时候不需要从其他系统运行如t()的代码)

何时使用t()

在如下情况中需要用到t()函数:

  • 当需要特别测试转义和定位功能时;
  • 当测试用户界面中已经解释的字符串。如:当验证一个403页面”Access denied”信息是,采用如下代码

<?php
$this
->assertText(t('Access denied'), 'Access denied message found on forbidden foo page.');
?>

注意:第一个字符串”Access denied”,由drupal_deliver_html_page()提供,用t()转义。因此,我们也用这个t()函数来检查这条消息是否存在。

何时不使用t()函数

不要在如下情况中使用t():

  • getInfo()中含字符串.
  • 测试语句消息,重复如上例子

<?php
$this
->assertText(t('Access denied'), 'Access denied message found on forbidden foo page.');
?>

第二个字符串’Access denied message found on forbidden foo  page’仅是注释信息,不要将它转义.

  • 除非测试模块需要测试转义功能,否则对于测试模块和主题输出不要使用。

在如上例子中,如果需要设置格式或定制字符串输出,可以用format_string()函数

Simpletests调试

在测试设置中(admin/config/development/testing/settings),有一个选项“Provide verbose information when running tests ".如果打开这个选项,则每个drupalGet()和drupalPost()函数将作为HTML文件被捕捉,以便让你浏览结果。这是个及其重要的工具。

你也可调用$this-> verbose(“Some message”)函数,如果verbose消息开关打开的话,函数中包含的消息就会显示出来。

更多的debug()$this-&gt;verbose()信息可以参考 Boombatower's blog about debugging in Drupal 7

进一步指南

  • 学习本章节叙述的几个API函数语句
  • 通读drupal_web_test_case.php是很有意义的

注: Google Docs presentation to go with this materialrfay维护。

Simpletest 使用指南(Drupal 6)

原文链接http://drupal.org/simpletest-tutorial

注:本指南中引用代码来自Examples for Developers module,你可以:

  • 从该模块中复制一份代码,编辑、修改然后进行测试.
  • 报告所发现问题,进行修复,欢迎进行补丁修正和提出改进意见。

通过本指南,可以让你掌握基本的测试方法。学习本节后你可以建立第一个测试!在本例中,我们将创建一个叫“simplest example”的dummy 模块,它提供一个叫”simplest_example” 的内容类型。 这个内容类型和任何基本drupal节点类型(如:’page’)一样。本指南将阐述如何对这个simplest_example内容类型进行测试,从而保证其功能的有效实现。

准备工作

首先,我们要确保simpletest模块已安装。在Drupal6中,simpletest属于contributed模块。你需要阅读模块目录下的INSTALL.txt文件,按说明操作,其中包括打补丁。

如果你还没有开始准备,请确保Simpletest模块已经启用。

学习本指南需要打开Simpletest Verbose开关。它能给出每一个测试阶段的Drupal页面截图。该选项在管理/配置/开发/设置(admin/config/development/testing/settings)下可以看到。

本指南所采用的例子取自http://drupal.org/project/examples

Drupal Simpletest如何工作

大多数Drupal功能是面向web的,因此演习这些功能是及其重要的。Simpletest生成一份完整的安装和一个虚拟的web浏览器,通过这个虚拟浏览器来进行一系列测试,就如你手工一步步进行一样。记住每次测试都是在运行一个完整的新的durpal实例是非常重要的。换而言之,每一个测试实例是空的,没有进行过任何配置,建立过任何用户,除了默认的内核模块,其他模块都未开启。如果你的测试需要一个有特权的用户,你就需要创建一个(这如同你手工创建一个测试环境一样)。如果有需要的模块,你就需要开启他们。如果需要配置,就要用simpletest来进行配置,因为在我们要测试的druapl实例中,该测试站点还未进行过任何配置,文件目录下也没有任何文件,也未安装过可选模块,也没有创建过任何用户。在simpletest中,我们有神奇的命令去执行它们,稍后我们会做进一步讲解。

关于Simpletest Example模块

Simpletest Example模块给出了一个可配置的节点类型(如’page’或者’story’).该类型有一个标题和一个正文组成。借此它给我们演示了测试内容创建的机会。为了实现这个节点,我们需要用hook_node_info()钩子函数来创建节点类型,用hook_form()函数来创建表单。我们需要为模块设置权限(为此你需要” create simpletest_example content”权限来创建,或者由”edit own simpletest_example content”取得编剧权限)。当然,我们需要准备一个simpletest_example.info文件。

注意,我们的模块中有一个bug:它的权限处理是有问题的。因此即使给予了’edit own simpletest_example’ 的字符串,simpletest_example_access()函数也不能正确处理,所以当我们赋予用户编辑节点权限室,实际上是不能实现的。当然,手工测试时可能一直用用户1来测试,不会看到测试失败的情况,我们稍后会提到。

本代码在Examples for Developers模块中维护,它有助于在正式发布前,用dummy代码来进行测试、编辑和实践,.建议开发者取些模块,启用并练习。

思考何时需要测试

如果已经安装了simpletest_example模块,你可以按如下步骤一步步来进行,并思考何时需要测试。

访问创建容->Simpletest Example (Create Content > Simpletest Example),你会看到如下页面。

查看界面并选定要测试的内容。

仔细浏览确保你已经熟知接口间是如何工作的,在一个基本实例,而不是Simpletest操作中,功能可以实现。如果你还没有理解原理,是不能写好测试代码的。在本例中,我们来填上标题和正文内容,然后按保存按钮。你将看到如下页面。

 对simpletest_example构建测试

好,我们可以来测试了,我们会在simpletest_example.test文件中操作。(该文件可从下载的模块中获得)

如果对一个模块添加了一个新的.test文件,你可能需要重刷Drupal缓存,让Drupal知道你有新文件了。要刷新缓存,可以去admin/settings/performance下点击“clear all chaches”按钮。

进行一个测试需要如下四个步骤:

  • 创建结构(即产生一个从DrupalWebTestCase继承的类)
  • 对任何用户创建或需要的配置的测试实例初始化
  • 用测试实例产生真实测试
  • 当然,要特别想清楚为什么我们的测试没有按预想地进行并调试测试(也许还有模块).

在开始前,我们需要模块扩展DrupalWebTestCase.

为了使Simpletest接口调用测试,我们来用getInfo()函数实现。它提供了用户接口信息,并在刷新缓存后,显示在simpletest页面上。

下面就是非常重要的setup()函数了。这里我们就要处理必须处理的,让该Drupal实例按我们的想法工作。我们必须考虑:“我们如何操作,才能从初始化安装到可以在哪里运行测试?在我们的实例中,我们知道必须:

  • 启用Simletest Exmaple模块
  • 创建一个有权限的用户,来产生一个simpletest_example 节点
  • 用该用户登陆

以上方法就是有setup()方法来实现的.

<?php
 
public function setUp() {
   
// Enable any modules required for the test.
   
parent::setUp('simpletest_example');

   
// Create and log in our privileged user.
   
$this->privileged_user = $this->drupalCreateUser(array('create simpletest_example', 'edit own simpletest_example'));
   
$this->drupalLogin($this->privileged_user);
  }
?>

注:我们必须启用所有关联模块。本例中没有,但是你的模块肯能有这种情况。这可以通过给parent::setup()传递多个参数的方法来实现。在有些情况下,必须按顺序来启用(比如:date_api需要在data 前启用)。举例如下:

<?php
 
public function setUp() {
   
// Must include every single module on which Meetings module relies.
   
parent::setUp(
     
'content',
     
'ctools',
     
'date_api',
     
'date',
     
'date_timezone',
     
'date_popup',
     
'features',
     
'filefield',
     
'token',
     
'messaging',
     
'notifications',
     
'notifications_content',
     
'notifications_team',
     
'strongarm',
     
'text',
     
'views',
     
'votingapi',
     
'meetings'
   
);
  }
?>

测试建立:创建节点

现在让我们来创建测试实例练习模块。刚才我们已经为我们的测试类建立了成员函数,每一个成员我们会来练习一个测试。

我们的第一个测试将通过node/add/simpletest-example中的form来创建一个新的simpletest_example节点.

<?php
 
public function testSimpleTestExampleCreate() {
   
// Create node to edit.
   
$edit = array();
   
$edit['title'] = $this->randomName(8);
   
$edit['body'] = $this->randomName(16);
   
$this->drupalPost('node/add/simpletest-example', $edit, t('Save'));
   
$this->assertText(t('Simpletest Example Node Type @title has been created.', array('@title' => $edit['title'])));
  }
?>

drupalPost, drupalGet和判断语句

以上代码在node/add/simpletest-example页面完成了一个简单的递交表单的功能。它将字段定义到了一个数列中($edit数组产生随机值赋给title和body),然后递交表单,并声明在页面上找到了合适的文本.

大多数的测试将按如下形式来进行:

  • 调用drupalGet()函数来跳转到一个页面或者用drupalPost()来递交表单
  • 用一次或多次语句来检查内容是所见即所得的.

$this->drupalGet($path)可以非常容易的跳到指定页面。

$this->drupalPost($path, $edit_fields, $submit_button_name)稍复杂些。

还有几十种这样的语句。最容易的一个是$this->assertText($text_to_find_on_page).当超越本指南知识后,你会想参阅更多的语句

通过Web界面运行Simpletest

下面我们来运行测试。这里我们将用web界面来运行。

访问管理->站点构建->测试(Admin->Site Building->Testing)。选择你要创建的测试-它会在”Examples”组下,点击并运行”Runtests”(有时可能需要清除Drupal缓存才能在列表中见到)

测试运行后你就能见到是否通过(pass)的结果。

你也可以通过命令行运行。更多的内容请参阅通过命令行来运行测试

一个失败测试的演示

测试成功的例子没有必要多讲了,现在我们来举一个失败的例子。

还是用相同的类,这次来测试编辑节点的情况。我们的模块有一个缺陷-它不能很好的处理”edit own simpletest_exple”权限,当用户仅有此权限时缺不能编辑它。在本实例中我们将创建一个节点,然后来进行编辑。

运行测试并查看结果。

<?php
 
public function testSimpleTestExampleEdit() {
   
$settings = array(
     
'type' => 'simpletest_example',
     
'title' => $this->randomName(32),
     
'body' => $this->randomName(64),
    );
   
$node = $this->drupalCreateNode($settings);

   
// For debugging, we might output the node structure with $this->verbose().
    // It would only be output if the testing settings had 'verbose' set.
   
$this->verbose('Node created: ' . var_export($node, TRUE));

    if (!
$this->runningOnTestbot()) {

     
// Make sure we don't get a 401 unauthorized response when editing.
     
$this->drupalGet("node/{$node->nid}/edit");
     
$this->assertResponse(200, t('User is allowed to edit the content.'));
     
// Looking for title text in the page to determine whether we were
      // successful opening edit form. Note that the output message
      //  "Found title in edit form" is not translated with t().
     
$this->assertText(t("@title", array('@title' => $settings['title'])), "Found title in edit form");
    }
  }
?>

单元测试

Simpletest也提供了DrupalUnitTestCase,来作为DrupalWebTestCase的可选类.

单元测试不会产生数据库表格和文件目录. 所以单元测试要比功能测试初始化快,但这也意味着它不能访问数据库和文件目录。调用任何一个需要数据库看函数会产生异常。这些函数包括routine 函数,比如像watchdog(), drupal_function_exists(), module_implements(), module_invoke_all() 等。

更多的编写单元测试的资料请参阅用Simpletest来进行单元测试

何时在Simpletest中用t()函数

和Drupal中的大多数字符串不同,simpletest的字符串不经常用到t()函数。这里有两个原因:

  1. 许多simpletest的字符串仅仅是测试目的,不会用到网站上,因此不需要解释它们。
  2. 当不同组件尽可能分开时,它能比较容易地提供永久、强大的覆盖面.(即:不需要时的时候不需要从其他系统运行如t()的代码)

使用t()函数的情况

在如下情况中需要用到t()函数:

  • 当需要特别测试转义和定位功能时;
  • 当测试用户界面中已经解释的字符串。如:当验证一个403页面”Access denied”信息是,采用如下代码

<?php
$this
->assertText(t('Access denied'), 'Access denied message found on forbidden foo page.');
?>

注意:第一个字符串”Access denied”,由drupal_deliver_html_page()提供,用t()转义。因此,我们也用这个t()函数来检查这条消息是否存在。

不使用t()函数的情况:

不要在如下情况中使用t():

  • getInfo()中含字符串.
  • 测试语句消息,重复如上例子

<?php
$this
->assertText(t('Access denied'), 'Access denied message found on forbidden foo page.');
?>

第二个字符串’Access denied message found on forbidden foo  page’仅是注释信息,不要将它转义.

  • 除非测试模块需要测试转义功能,否则对于测试模块和主题输出不要使用。

在如上例子中,如果需要设置格式或定制字符串输出,可以用format_string()函数

Simpletests调试

在测试设置中(D6: 管理/构建/测试/设置admin/build/testing/settings, D7: 管理/配置/开发/设置admin/config/development/testing/settings),有一个选项“Provide verbose information when running tests ".如果打开这个选项,则每个drupalGet()和drupalPost()函数将作为HTML文件被捕捉,以便让你浏览结果。这是个及其重要的工具。

你也可调用$this-> verbose(“Some message”)函数,如果verbose消息开关打开的话,函数中包含的消息就会显示出来。

进一步指南

  • 学习本章节叙述的几个API函数语句
  • 通读drupal_web_test_case.php是很有意义的

注: Google Docs presentation to go with this materialrfay维护。

Simpletest 的单元测试

原文链接http://drupal.org/node/811254

注:本指南的代码由Examples for Developers module维护,也就是说:

  • 从该模块中复制一份代码,编辑、修改然后进行测试.
  • 报告所发现问题,进行修复,欢迎进行补丁修正和提出改进意见。

Simpletest通过DrupalWebTestCase提供了强大的测试功能,但有时你可能只想写一个传统而简单的单元测试。Simpletest也提供了这样的功能。在本页中我们就通过举例来介绍单元测试方法。

要测试什么呢?

单元测试的目的是要测试一段独立的功能,如函数或方法。例如:某个模块带有实现如下功能的函数。

<?php
function simpletest_example_empty_mysql_date($date_string) {
    if (empty(
$date_string) || $date_string == '0000-00-00' || $date_string == '0000-00-00 00:00:00') {
       
$date_is_empty = true;
    }
    else {
       
$date_is_empty = false;
    }

    return
$date_is_empty;
}
?>

 我们应该在各种条件下来测试该函数。在上述例子中,我们仅测试一些值:NULL,空字符串, '0000-00-00',和一个有效的日期。

构建测试

首先我们需要来创建一个测试文件。在模块目录下,产生一个新的.test文件。在本例中,即simpletest_example.test文件。

为了让Drupal知道这个测试,需要在模块的.info文件中将你的测试文件加到'file[]’参数中。在本例中,我们在simpletest_example.info中添加:

files[] = simpletest_example.test

 现在我们回到’simpletest_example/simpletest_example.test’文件,为单元测试产生一个类。这个类将扩展DrupalUnitTestCase.

<?php
class SimpletestUnitTestExampleTestCase extends DrupalUnitTestCase {

}
?>

 像扩展DrupalWebTestCase一样,我们的SimpletestUnitTestExampleTestCase类需要通过getInfo()方法实现。该方法在simpletest页上有详细描述:

<?php
public static function getInfo() {
 
// Note: getInfo() strings should not be translated.
 
return array(
   
'name' => 'Simpletest Example unit tests',
   
'description' => 'Test that simpletest_example_empty_mysql_date works properly.',
   
'group' => 'Examples',
  );

}
?>

 我们写完getInfo()后,就可以正式写我们的单元测试。所有的单元测试方法应该以小写’test’开始。所有用这种方法开始的都自动被simpletest识别,然后按要求运行。尽管不同的判断语句可以放到不用的方法中,但是推荐一次性测试不同的判断语句,这可由如下方法实现:

<?php
function testEmptyMySQLDate() {

 
$result = simpletest_example_empty_mysql_date(NULL);
 
// Note: Test output messages should not be translated.
 
$message = 'A NULL value should return TRUE.';
 
$this->assertTrue($result, $message);

 
$result = simpletest_example_empty_mysql_date('');
 
$message = 'An empty string should return TRUE.';
 
$this->assertTrue($result, $message);

 
$result = simpletest_example_empty_mysql_date('0000-00-00');
 
$message = 'An "empty" MySQL DATE should return TRUE.';
 
$this->assertTrue($result, $message);

 
$result = simpletest_example_empty_mysql_date(date('Y-m-d'));
 
$message = 'A valid date should return FALSE.';
 
$this->assertFalse($result, $message);

}
?>
好,以上就是我们的全部测试代码。很明显,在语句前你需要做复杂的安装,但是单元测试还是比由DrupalWebTestCase提供的全面性的功能测试简单的多。 写完单元测试,清空缓存后,对Drupal6和Drupal7分别进入如下目录来运行测试。

开始使用 SimpleTest

原文链接http://drupal.org/node/291740

请阅读本章节内容,来了解drupal的测试方法。

安装和配置

原文链接http://drupal.org/node/519364

要求

虽然SimpleTest有一些非默认配置要求,但是无论Simpletest 6.x-2.x,还是作为drupal 7 核心的SimpleTest,其要求是一致的。因为测试可能需要执行任何一个模块,所以除了满足如下要求外,所有的核心要求都要得到满足。

  • PHP CURL扩展插件
  • PHP DOM扩展插件.在PHP5中已为默认支持。
  • PHP内存要求推荐位256MB(不一定要精确)。

Drupal 7.x

  1. SimpleTest 在7.x中已经是核心模块,即:测试模块。在管理/模块admin/modules下启用它.
  2. 如有必要,可以去如下路径配置HTTP认证:admin/config/development/testing/settings

环境

和浏览器一下,SimpleTest需要有一定的权限来访问你的开发网站(即:HTTP认证、防火墙)。

当满足以上条件后,就可以启用SimpleTest了。

默认配置请参阅SimpleTest的INSTALL.txt 文件。

运行测试

原文链接http://drupal.org/node/30036

完成安装和配置后,就可以来进行测试了

  1. 访问管理/配置/开发/测试admin/config/development/testing(Drupal6中为:管理/构建/测试admin/build/testing),可以看到所有测试项安组归类的测试列表。
  2. 选择想要运行的测试或测试组.
  3. 在页面的最后点击RUN按钮。

测试完成后,会显示测试结果,失败的测试结果会扩展开来显示。

测试故障排除

原文链接http://drupal.org/node/394976

选用新增debug()函数

如果你在drupal7中使用最新版的simpletest, 你就可以使用该调试功能。调试功能和verbose信息在该链接处阐述:

输出随即变量

你经常需要输出变量来查看内容。在simpletest中这很难实现,但是你可以将它们赋给相关pass的测试消息语言来输出到屏幕上。

<?php
$var
= $this->doAwesomeStuff($settings);
$this->pass(var_export($var, TRUE));
?>

浏览当前页面内容

许多测试可以得到一个页或者提交到一个页面。通过在simpletest的设置中启用’verbose’模式,你就可以在测试结果中通过连接来查看每个页面的内容。注意这不是供实际用户浏览、展现页面内容的好方法。比如:上传图像会正常渲染,但是浏览者却看不到。(特别这是因为:当你浏览HTML时,这些测试文件已经不存在了。他们在simpletest的清除过程中被删除了) 。

你也可以用如下代码将输出页写到你站点根目录下的一个文件中。

<?php
file_put_contents
('output.html', $this->drupalGetContent());
?>

 

从一个GET返回0字节

有时我们可能得到如下消息:

" GET http://example.local/memberreturned 0 (0 bytes)。

这个错误信息,通常表示你的站点白屏了,也可能是由于DNS解析不对引起,或其他错误导致HTTP请求失败。请确保服务器端HTTP状态测试正常,如果失败了则按如下方法修改:比如:增加你要访问站点的DNS记录,修改防火墙或SE Linux设置。

测试开始就失败

如果在一开始你就遇到测试失败,则要检查和确保站点只有英语,而不是多语言设置。如果你的url有法语,则要切回英文或移走该语言前缀,则你的问题就可以解决。

xdebug

Simpletest reference Tips 专门有章节在最后介绍xdebug.

SimpleTest 上传测试悬挂

故障现象

SimpleTest在Mac OS X系统上上传任何文件时不会结束,涉及的系统有Leopard和其他版本。

问题描述

 在Mac OS上似乎cURL被破坏了,cURL的版本在10.5.7OS应该是cURL7.16.3.

解决方法

一个解决方法是在源重新编译cURL和PHP。不过最简单和最易管理的方法是用MacPorts安装开发环境。你可以在不同的端口并行运行两个环境,设置不同的运行时间或者完全取代Apache+PHP安装。

如果已经安装了MacPorts,这个过程需要20到30分钟时间。如果是第一次安装MacPorts,则根据你的计算机的速度,也许要1个小时。

首先,安装MacPorts.

*参见更多的 verbose指令集[off-site]

用SSL更新cURL:

sudo port install curl +ssl

安装 Apache 2:

sudo port install apache2

安装PHP 5

sudo port install php5 +apache2 +mysql5 +pear

配置Apache

sudo cp /opt/local/etc/php5/php.ini-dist /opt/local/etc/php5/php.ini sudo cp /opt/local/apache2/conf/httpd.conf.sample /opt/local/apache2/conf/httpd.conf

激活PHP 5模块

cd /opt/local/apache2/modules sudo /opt/local/apache2/bin/apxs -a -e -n &quot;php5&quot; libphp5.so

你也许需要在httpd.conf文件中在<IfModule mime_module>区块下添加如下几行:

AddType application/x-httpd-php .php AddType application/x-httpd-php-source .phps

你也可能要在区块下添加index.php。

完成Apache配置。 运行和停止Apache

Apache将由launchd管理. 用如下命令启动Apache:

sudo launchctl load -w /Library/LaunchDaemons/org.macports.apache2.plist

这样机器重启的是时候Apache会自动启动

停止apach用如下命令:

sudo launchctl unload -w /Library/LaunchDaemons/org.macports.apache2.plist

即使自动启动也会停止Apache。

 

SimpleTest (浏览器)在Vista上故障

原文链接http://drupal.org/node/304216

故障现象

当你的主机(或任何系统)运行在windows Vista上是,基于SimpleTests的[浏览器]会运行失败。

问题

Windows Vista在它的主机文件中添加了一行,阻止了SimpleTest浏览器通过SimpleTests的stock.php中的代码来获取页面。

function _openSocket($host, $port, &amp;$error_number, &amp;$error, $timeout) { return @fsockopen($host, $port, $error_number, $error, $timeout); }

解决方案

  1. 以管理员身份运行notepad(找到notepad,右击鼠标,以管理员运行)
  2. 找到hosts文件(c:\windows\system32\drivers\etc\hosts)
  3. 查找如下行,删除或注释掉。
    ::1 localhost
  4. 重启apache
  5. 顺利运行SimpleTest[浏览器]测试

 

 

管理测试实例

原文链接http://drupal.org/node/583030

在许多模块中不同的测试实例需要在不同的上下文中运行。比如,一组测试可能需要将测试数据写入数据库;另一组也许需要产生模块表,但找过模块的_install函数。

DrupalWebTestCase和DrupalUnitTestCase 可以扩展来处理这些情况。你可以在modules/simpletest/tests/database_test.test文件中查看这种方法。

集中创建用于测试的样本数据

为了取得一致和节省时间,你可以在一个类中产生所有的样本数据,然后让你的测试实例来继承。

<?php
class MyModuleWebTestCase extends DrupalWebTestCase {
  function
setUp() {
   
parent::setUp('mymodule');
   
// Insert your data into the database here
    // Use db_insert() etc. Hard coded SQL will affect your actual drupal installation, not your test environment
 
}
}

class
MyModuleExampleTestCase extends MyModuleWebTestCase {

 
// No setUp() function necessary, because the setUp is inherited

 
public static function getInfo() {
    ...
  }

  function
testExample() {
   
// Your test(s) here
 
}
}
?>

注:在你的父类(MyModuleWebTestCase 以上)不要声明getInfo()或任何测试方法(如:testExample()),否则会产生错误。

模块化你的测试实例

最好的测试实例是小型模块化--在测试实例中,每一种方法如testExample()应该能测试小片代码或功能。

测试数据库不要增加模块安装开销

这是种高级技术,大多数测试者不需要用到。

测试不需要任何数据库功能,只需要扩展DrupalUnitTestCase,但如果需要测试你的模块和数据库的交互而不启用整个模块,你可以使用drupal_install_schema() 函数来创建所需表格。

<?php
class MyModuleDatabaseTestCase extends DrupalWebTestCase {
  function
setUp() {
   
// Create the module's tables without running hook_install or hook_enable
   
drupal_install_schema('mymodule');
  }
}

class
MyModuleSchemaTestCase extends MyModuleDatabaseTestCase {

 
// No setUp() function necessary, because the setUp is inherited

 
public static function getInfo() {
    return array(
     
'name' => 'Database functions test',
     
'description' => 'Tests CRUD functions',
     
'group' => 'My Module',
    );
  }

 
/*
   * Tests that parent class created module tables
   */
 
function testSchemaCreated() {
   
// Your test(s) here
 
}
}
?>

写升级测(Drupal 7/8)

本章节阐述了如何为drupal内核升级编写测试代码,包括:

  • 重大内核版本升级(如,从7.x到8.x)
  • 小版本内核升级(如,从7.10到7.12)。

升级测试需要数据库dump

升级测试就是一个“普通”的测试,除了它不需要进行新数据库安装。他们需要先导入一份老druapl版本的数据库dump。回顾现行的升级有:

数据库导出使用PHP文件,通过数据库API接口来创建希望的后端schemas和数据。举例如下: 

  • drupal-6.bare.database.php 含有schemas的大量dump,但是含的数据不多
  • drupal-6.comments.database.php 含有具体的注释测试的数据。
  • 测试可以用到这些dump的任何一个,甚至可以加载一系列的dump来做复杂的设置。请参阅下面详细信息。

    数据库的dump可以用gzip来压缩,但不是必须的。Drupal 7大多采用一般的PHP文件。在撰写本文是,Drupal8已只采用.gz压缩文件。gzip压缩的文件很难做diff,但是check out和发布时文件要小的多。

    创建测试用的数据库dump文件

    数据库dump文件是些php文件,通过数据库API接口文件来创建所要schema和导入所需数据。这些文件可以从一个已安装的Drupal数据库用内核中的脚本来生成。

    创建数据库dump的步骤

    1. 首先检查是否在Drupal7或Drupal8升级测试中已有合适的供升级的dump组件(如果适用的话)。

  • 如果有合适的数据库dump存在,用该dump来安装 Drupal。(许多情况下,你可以简单的通过阅读klausi'的博客来选择其中一种方法来完成)。
  • 如果没有合适的dump存在,或者你在已有的配置上需要增加其他的测试,则通常需要安装Drupal的预升级版本。
  • 2. 用测试需要的最低限度的更改来配置Drupal。比如,你需要为某个特别模块增加测试,就启用并配置该模块。

    3. 用适当的shell脚本来生成新的数据库dump

  • 对于Drupal7->8,采用core/scripts/dump-database-d7.sh
  • 对于For Drupal 6 -> 7, 用scripts/dump-database-d6.sh
  • 4.将数据库dump添加到你的patch中

  • 如果你产生的是新文件,则用git add 将该文件添加到patch中.
  • 如果是更新已经的dump,要确保只将需要的更改添加到dump文件。你要手工将这些更改从已经的文件复制到生成的文件中。
  • 如果需要更新的文件已经gziped压缩,则解压dump,进行更改后,再gzip压缩该dump.你必须用git diff --binary来讲所做的修改写入压缩文件中.
  • 请注意,你可以通过在已有的完整的dump上,生成仅含有和该模块相关数据的第二份文件,来为另外的模块添加测试。例如:参阅drupal-6.comments.database.php。该dump文件需要drupal-6.filled.database.php来安装drupal,然后可以简单地为测试添加额外的注释数据。

    创建新数据库dumps的Shell脚本

    在运行脚本前,假定你已经安装了Drush.安装指南请参阅Drush的README.txt文件。

    # Remove any previous installation of Drupal in the druapl-dumps directory.
    rm -rf drupal-dumps/drupal

    # Download the latest D7, place it in 'drupal-dumps' directory,
    # rename the downloaded directory 'drupal'.
    drush dl drupal-7.x --destination=drupal-dumps --drupal-project-rename=drupal

    cd drupal-dumps/drupal

    # Install Drupal site using the standard profile
    # and create an SQLite database.
    drush site-install -y standard --account-name=admin --account-pass=drupal --db-url=sqlite:./.ht.drupal.sqlite

    # enable all core modules
    drush pml --core --status="not installed" --pipe | xargs drush en --yes

    # Create a database dump of the empty Drupal site.
    php scripts/dump-database-d7.sh > ../d7.standard.bare.php

    # Generate content in the Drupal site.
    php scripts/generate-d7-content.sh

    # Create a database dump of the Drupal site.
    php scripts/dump-database-d7.sh > ../d7.standard.filled.php

    写升级测试

    从UpgradePathTestCase扩展测试类

    要测试已有的实用功能(如更容易的加载数据库dump, 运行update.php等),需要从基本升级路径类扩展你的测试类,提供getInfo()方法如其他测试方法一样。
  • 重大版本升级(如,Drupal 6 -> Drupal 7),扩展UpgradePathTestCase。
  • 小版本升级(如,Drupal 7.0 -> 7.x),扩展UpdatePathTestCase。
  • (也可参阅#1430412: 考虑重大版本和小版本升级测试的命名规范

    以Drupal7的upgrade.commment.test为例

    <?php
    /**
    * Tests the upgrade path for the Comment module.
    */
    class CommentUpgradePathTestCase extends UpgradePathTestCase {
      public static function
    getInfo() {
        return array(
         
    'name'  => 'Comment upgrade path',
         
    'description'  => 'Comment upgrade path tests.',
         
    'group' => 'Upgrade path',
        );
      }

     
    // ...
    }
    ?>

    升级测试的setupUp()方法

    测试可以使用任何一个已有的dump,甚至用复杂的配置,加载一系列dumps来测试系统。如上所述,upgrade.comment.php同时加载数据库dump和自己的注释数据库dump来准备环境。

    <?php
     
    public function setUp() {
       
    // Path to the database dump files.
       
    $this->databaseDumpFiles = array(
         
    drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-6.filled.database.php',
         
    drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-6.comments.database.php',
        );
       
    parent::setUp();
      
    // ...
     
    }
    ?>

    将升级方法运用到测试实例

    一旦升级测试的setUp()方法从dump php文件导入了数据库dump,测试方法就可以编写功能测试了。但是要确保在升级前,先在测试函数中进行升级,和/或者进行数据的更改。upgrade.locale.test文件枚举了大量的例子。

    <?php
     
    /**
       * Tests an upgrade with path-based negotiation.
       */
     
    public function testLocaleUpgradePathDefault() {
       
    // LANGUAGE_NEGOTIATION_PATH_DEFAULT.
       
    $this->variable_set('language_negotiation', 1);

       
    $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.');

       
    // The home page should be in French.
       
    $this->assertPageInLanguage('', 'fr');

       
    // The language switcher block should be displayed.
       
    $this->assertRaw('block-locale-language', 'The language switcher block is displayed.');

       
    // The French prefix should not be active because French is the default language.
       
    $this->drupalGet('fr');
       
    $this->assertResponse(404);

       
    // The English prefix should be active.
       
    $this->assertPageInLanguage('en', 'en');
      }
    ?>
    其中,$this->performUpgrade() 函数部分是实现升级运行,这样你的升级方法得到了一个升级环境。这里,我们在执行升级前,进行不同的设置,这样就可以测试升级。

    性能:提高 Simpletest 在开发中的速度

    原文链接http://drupal.org/node/466972

    • 调整MySQL 配置
      尽管InnoDB被推荐在实际环境系统中使用,但对测试伺服器不是很理想,因为DDL操作(表创建/表删除)要比MyISAM慢的多。
    • 将MySQL数据库移到tmpfs中
      测试伺服器在短时间内发布大量的查询(特别是DDL查询)会增加数据库服务器负担。某些查询后,数据库服务器会明显地刷新数据到磁盘(MySQL试图避免这种可能的情况,但是它还是会在一个DLL操作后调用fsync()函数)。数据库文件移入到tmpfs文件系统则结果大为不同。
    • 调整PostgreSQL 配置
      默认情况,PostgreSQL服务器将通过发出fsync()系统调用或各种等效方法,尽量确保所做更新在物理上写到磁盘中。这会在测试过程中产生大量的I/O读写。
    • 将SQLite数据库保存到内存
      将SQLite数据库保留在内存后,大量的磁盘I/O读写就看避免,从而加快整个过程。请注意,这意味着每次重启机器后,数据库必须重建。

    调整MySQL配置

    将如下代码写入到my.cnf中

    skip-innodb

    将此设置写入到[mysqld]下非常重要,否则就不起作用。

    将MySQL数据库提到tmpfs系统中

    tmpfs是linux的pseudo文件系统,它将文件和目录存到内存中。重启后放入tmpfs中的文件会丢失,但对测试伺服器没有关系。

    要将数据库移入tmpfs,将如下代码写入/etc/fstab中:

    tmpfs /var/lib/mysql/drupal_checkout tmpfs rw,nosuid,nodev,noexec,uid=<uid mysql="" of="" the="" user="">,gid=<gid group="" mysql="" of="" the=""> 0 0</gid></uid>

    <uid of the mysql user>和<gid of the mysql group>可以分别在/etc/passwd和/etc/group下找到

    调整PostgreSQL配置

    为了不让PostgreSQL每次修改都写入到磁盘,在postgresql.conf文件中设置fsync=off。请注意,当系统崩溃时会引起严重的数据丢失,所以在测试数据库服务器上使用要特别留意,千万不要在生产服务器上使用。

    将SQLite数据库存入内存

     要将SQLite数据库整个放入内存,在linux上可以在/dev/shm中选择一个文件作为数据库路径下。

     

    附件尺寸
    Plain text icon mysql-tmpfs.txt5.92 KB
    Plain text icon mysql-reference-cfg.txt909 字节

    通过命令行执行测试

    原文链接http://drupal.org/node/645286

    命令行执行测试--linux平台

    本章节供那些希望或者需要命令行来运行测试套件者阅读。这方法会经常用到在,比如当想整合第三方系列工具,的时候。当你只希望做小规模的,测试一个或几个模块式式,我希望本页面能收集测试方面的信息和技巧。

    对于想通过GUI来运行SImpletest的开发者,请阅读Simpletest指南 ; 深入阅读指南,你会发现通过Durpal用户界面来运行测试的一些信息。通过drupal界面以命令行访问Simpletest的两个重要链路是admin/config/development/testing/ and admin/config/development/testing/results。

    位于/scripts下有个run-tests.sh的帮助文件,它使在Drupal中,通过命令行执行测试变得非常容易。你可以作为web服务器端用户,去站点的根目录下,执行php scripts/run-tests.sh,就可以很容易地执行测试套件。

    如果你不喜欢每次都输入/scripts/run-test.sh,在你的路径下如果存在bin目录,则可以在~/bin目录下建一个symlink符号连接,如下显示:

    ln -s scripts/run-tests.sh ~/bin

    运行不带参数的脚本可以弹出帮助页面,并给出option列表。

    下面我们来全面地展开run-scripts.sh:

    www-data@dev:/var/www-drupal-7-head$ php scripts/run-tests.sh

    Run Drupal tests from the shell.

    Usage:        run-tests.sh [OPTIONS] <tests>
    Example:      run-tests.sh Profile

    All arguments are long options.

      --help      Print this page.

      --list      Display all available test groups.

      --clean     Cleans up database tables or directories from previous, failed,
                  tests and then exits (no tests are run).

      --url       Immediately preceeds a URL to set the host and path. You will
                  need this parameter if Drupal is in a subdirectory on your
                  localhost and you have not set $base_url in settings.php.

      --php       The absolute path to the PHP executable. Usually not needed.

      --concurrency [num]

                  Run tests in parallel, up to [num] tests at a time. This requires
                  the Process Control Extension (PCNTL) to be compiled in PHP, not
                  supported under Windows.

      --all       Run all available tests.

      --class     Run tests identified by specific class names, instead of group names.

      --file      Run tests identified by specific file names, instead of group names.
                  Specify the path and the extension (i.e. 'modules/user/user.test').

      --xml <path>

                  If provided, test results will be written as xml files to this path

      --color     Output the results with color highlighting.

      --verbose   Output detailed assertion messages in addition to summary.

      <test1>[,<test2>[,<test3> ...]]

                  One or more tests to be run. By default, these are interpreted
                  as the names of test groups as shown at
                  ?q=admin/config/development/testing.
                  These group names typically correspond to module names like "User"
                  or "Profile" or "System", but there is also a group "XML-RPC".
                  If --class is specified then these are interpreted as the names of
                  specific test classes whose test methods will be run. Tests must
                  be separated by commas. Ignored if --all is specified.

    To run this script you will normally invoke it from the root directory of your
    Drupal installation as the webserver user (differs per configuration), or root:

    sudo -u [wwwrun|www-data|etc] php ./scripts/run-tests.sh  --url http://example.com/ --all
    sudo -u [wwwrun|www-data|etc] php ./scripts/run-tests.sh  --url http://example.com/ --class UploadTestCase

    用Drush来实现命令行执行测试--Linux平台

    Drush后面跟一些命令可以来协助测试:

    drush test mail : 运行测试套件,将结果发送到站点邮件.
    drush test clean: 清除测试套件表和遗留的文件.
    drush test drush : 测试drush (似乎只对drush有效)。

    请阅读代码。本页浅表性地介绍地执行测试的脚本可以扩展,并可按自己的想法重复使用。

    友好建议:

    • 确保你是以web服务器端用户来运行测试。
    • 如果你是通过远程shell在CLI上运行测试,screen(1) 实用工具对于长时间的测试会话很有效
    • Xdebug扩展可能和有些测试有冲突。
    • 或者禁用Xdebug,或在php.ini文件中[xdebug]下添加 xdebug.max_nesting_level=500.

    命令行执行测试--Windows平台

    Windows用户没有现成的.bat文件来容易地实现命令行测试。我认为编译一个.bat文件或安装cygwin来运行linux指令会更容易些。欢迎Windows开发者们来更新本章节,介绍最合适在windows平台使用的命令行测试。

    SimpleTest 参考

    原文链接http://drupal.org/node/278126

    本文如下给出了有关Drupal测试的其他资源。详细内容请阅读相关的链接页。

    关于以前版本的SimpleTest的信息,其文档中提及的钩子函数、方法和函数在本版本的SImpleTest中已经不使用。

    SimpleTest PHP库 (基于Drupal SimpleTest模块)。

    API函数

    原文链接http://drupal.org/node/265762

    内部浏览器

    DrupalWebTestCase设有一个内部浏览器,用作测试网站上的浏览。更多信息请阅读有关WebTestCase类的基础文档。

    function $this-&gt;drupalGet($path, $options = array())

    该函数向Drupal页面提出GET请求。
    其中,$PATH指要访问的页面的路径,$options给出可能需要提供给要访问页面路径的url()函数的其他一些数据。加载后的内容,会存储到$this->_content 中(和返回一样),可通过this->drupalGetContent()函数来获取内容

    请参加API文档来了解更多的url()函数(http://api.drupal.org/api/function/url)中如何构造$option关联数组的信息。

    function $this->drupalPost($path, $edit, $submit, array $options = array(), array $headers = array())

    该函数向Drupal页面提出post请求。

    • $path表示页面中含有的表单,显示$edit中的数据;
    • $option值传递给url(),以便建立$path的路径;
    • $sumbit用于发送按钮的点击(submit显示标题有该方法解释传递)
    • 表示HTTP表头的$head为POST操作的可选参数;
    • $edit数据应该是一组数组,其中索引值为HTML表单元素的"名字"属性值。可以通过像firebug这样的插件来获得该值。

    该函数也判断请求是否成功,表单字段从而可以设置。

    举例说明:

    <?php
    $name
    = $this->randomName();
    $mail = "$name@example.com";
    $edit = array(
     
    'name' => $name,
     
    'mail' => $mail,
     
    'status' => FALSE, // checkboxes must be set with TRUE/FALSE rather than 1/0
    );
    $this->drupalPost('user/register', $edit, 'Create new account');
    ?>

    注意:这里调用的是是drupalPostRequest()。

    对于多步骤表单,可以通过赋$path以$NULL值,从而使连续post表单成为可能。

    function $this->clickLink($label, $index = 0)
    该函数给出当前页面名字的链接。链接路径有第一个默认链接文本,或者后面的$index给出。

    举例如下:

    <?php
    $this
    ->clickLink(t('Log out'));
    ?>
    function $this->drupalCreateUser($permissions = NULL)

    该函数创建用户,并返回含有pass_raw值的用户对象,该pass_raw参数含non-hashed密码。

    该函数通过给返回用户对象定义$permissions来创建权限。

    $permissions为一组字符串数组。如果忽略还参数或者赋值NULL,那么注册用户权限则使用默认权限,

    array('access comments', 'access content', 'post comments', 'post comments without approval')

    结果会对成功做判断,同时清理用户和权限表。

    function $this->drupalLogin($user = NULL)

    该函数产生用户登陆网页后日志。只需对$user参数操作(需要给出pass_raw值)。

    如果忽略参数,则用上述提到的默认权限来产生用户和其权限。

    用户登陆后,就看用内置浏览器来浏览了。

    举例如下:

    <?php
    // Prepare a user to do the stuff
    $user = $this->drupalCreateUser(array('access content', 'create page content'));
    $this->drupalLogin($user);

    // Now do something with the users
    $this->drupalGet('node/' . $node->nid));
    ?>

    上述例子也对登陆过程做了几个判断。

    function $this->drupalLogout()

    该函数执行退出当前登陆。因为该函数通过$this->drupalLogin($user = NULL)自动调用的,所以要切换到另一个用户时,是不需要调用这个函数的。除非想退出当前登陆,切换到匿名登陆是才需要调用它。

    举例如下:

    <?php
    // Prepare a Drupal user to retrieve a page
    $user = $this->drupalCreateUser(array('access content', 'create page content'));
    $this->drupalLogin($user);
    $test_page = 'node/' . $node->nid;

    // Retrieve page as the logged in user
    $this->drupalGet($test_page);
    $this->assertText(t('Welcome'), t('Check that a welcome message is set'));

    // Logout and retrieve the page as an anonymous user
    $this->drupalLogout();
    $this->drupalGet($test_page);
    $this->assertText(t('Please login'), t('Check that user is prompted to login'));
    ?>

    注意:上例中需要退出,因为浏览器上已经有登陆会话了。如果你没有登陆一直以匿名用户在浏览网页,当然不需要退出。

    function $this->_drupalCreateRole($permissions = NULL)

    该函数很少用。$permission参数用法和drupalCreateUser一样。

    返回值是整型role-id,或者失败时以FALSE返回。

    function $this->randomString($number = 8)

    该函数返回$number参数唯一前缀字符串。该字符串为32到126之间的ASCII字符串。第一位字符不能为数字。

    function $this->randomName($number = 8)

    返回$number的唯一前缀字母字符串,第一个字母不能为数字。

    function $this->drupalCreateContentType($settings)

    该函数产生基于默认配置的自定义内容类型。节点的默认值已经设好,可以选择覆盖它们(或者通过$settings关联数字添加新的数值)。

    举例如下:

    <?php
    $settings
    = array(
     
    'type' => 'my_special_node_type', // Override default type (a random name)
     
    'title_label' => 'Name', // Override default title label ("Title")
     
    'body_label' => 'Description', // Override default body label ("Body")
    );
    $content_type = $this->drupalCreateContentType($settings);

    $this->assertEqual($content_type->type, 'my_special_node_type'); // We set this.
    ?>
    function $this->drupalCreateNode($settings)

    该函数产生一个节点。节点的默认值已经设置好,可以选择覆盖它们(或者通过$settings关联数字添加新的数值)。

    举例如下:

    <?php
    $settings
    = array(
     
    'type' => 'my_special_node_type', // This replaces the default type
     
    'my_special_field' => 'glark', // This appends a new field.
    );
    $node = $this->drupalCreateNode($settings);

    $this->assertEqual($node->type, 'my_special_node_type'); // We set this.
    $this->assertEqual($node->comment, 2); // This is default.
    ?>

    默认设置如下所示:

    <?php
       
    // Populate defaults array
       
    $defaults = array(
         
    'body'      => $this->randomName(32),
         
    'title'     => $this->randomName(8),
         
    'comment'   => 2,
         
    'changed'   => time(),
         
    'format'    => FILTER_FORMAT_DEFAULT,
         
    'moderate'  => 0,
         
    'promote'   => 0,
         
    'revision'  => 1,
         
    'log'       => '',
         
    'status'    => 1,
         
    'sticky'    => 0,
         
    'type'      => 'page',
         
    'revisions' => NULL,
         
    'taxonomy'  => NULL,
        );
       
    $defaults['teaser'] = $defaults['body'];
       
    // If we already have a node, we use the original node's created time, and this
       
    if (isset($defaults['created'])) {
         
    $defaults['date'] = format_date($defaults['created'], 'custom', 'Y-m-d H:i:s O');
        }
        if (empty(
    $settings['uid'])) {
          global
    $user;
         
    $defaults['uid'] = $user->uid;
        }
    ?>
    function $this->cronRun()

    该函数实现SimpleTest中Drupal安装的cron功能。千万不要直接调用drupal_run_cron。在Simple Test6.x中不存在这个方法。