关于
本文主要介绍了Robot Framework的重要组件。可以快速浏览该文和相关示例来了解该框架。该框架重要的特性,本文都会涉及。本文主要翻译于RF官方快速文档及个人理解。
RF概述
RF框架是用于验收测试和验收测试驱动开发(ATDD)的通用开源测试框架。它具备易于使用的表格测试数据语法,并且使用关键字驱动测试的方法。它的测试功能可以通过使用python或java实现的测试库来进行扩展,用户可以使用用于创建测试用例的相同语法从现有的关键字创建新的更高级别的关键字。
RF框架独立于操作系统和应用程序。核心框架是使用python实现的,可以在jython(JVM)和IronPython(.NET)上运行。该框架具有丰富的生态系统,包括作为单独项目开发的各种通用测试库和工具。
关于RF和其生态系统的更多信息,参阅http://robotframework.org.后续,本站也会进行更详细的梳理。
应用演示
本文的应用示例程序是传统登录示例的一个变体:它是基于一个命令行的python编写的身份验证服务器。该应用程序允许用户做以下三件事: * 创建一个有效密码的账号 * 使用有效的用户名和密码登陆 * 更改现有账号的密码
应用程序本身在sut/login.py文件中,可以使用命令python sut/login.py执行。尝试使用不存在的用户账号或密码无效登录会导致相同的错误信息:
> python sut/login.py login nobody P4ssw0rd
Access Denied
创建具有有效密码登陆的用户账号后:
> python sut/login.py create fred P4ssw0rd
SUCCESS
> python sut/login.py login fred P4ssw0rd
Logged In
密码必须符合两个要求:必须在7-12个字符之间,它必须包含大小写的字母和数字,但不能包含特殊字符。尝试创建无效密码的用户:
> python sut/login.py create fred short
Creating user failed: Password must be 7-12 characters long
> python sut/login.py creadt fred invalid
Creating user failed: Password must be a combination of lowercase and uppercase letters and numbers
使用无效凭据修改密码会导致和使用无效凭据登陆相同的报错信息。验证新密码的有效性,如果无效,则会显示错误信息:
> python sut/login.py change-password fred wrong NewP4ss
Changing password failed: Access Denied
> python sut/login.py change-password fred P4ssw0rd short
Changing password failed: Password must be 7-12 characters long
> python sut/login.py change-password fred P4ssw0rd NewP4ss
SUCCESS
应用程序使用简单的数据库文件来跟踪用户状态。该文件位于与操作系统相关的临时目录中。
执行指南
安装
在python上安装RF推荐使用pip。
pip install robotframework
关于其他的安装方式,请参考RF的安装说明。
示例中的代码块中的RF测试数据采用reStructuredText标记语言(python中很多说明文档都采用该格式,类似markdown)编写。 执行该格式的用例需要安装docutils模块:
pip install docutils
注意:Robot Framework 3.0 是第一个支持Python3的RF版本。
执行
安装完成后,需要获取示例本身。最简单的方式就是clone
当安装完成并且所有准备就绪后,可以使用robot命令执行。
robot QuickStart.rst
如果你是RF2.9或更新版本,可以使用pybot来替代robot:
pybot QuickStart.rst
执行log:
==============================================================================
QuickStart
==============================================================================
User can create an account and log in | PASS |
------------------------------------------------------------------------------
User cannot log in with bad password | PASS |
------------------------------------------------------------------------------
User can change password | PASS |
------------------------------------------------------------------------------
Invalid password | PASS |
------------------------------------------------------------------------------
User status is stored in database | PASS |
------------------------------------------------------------------------------
QuickStart | PASS |
5 critical tests, 5 passed, 0 failed
5 tests total, 5 passed, 0 failed
==============================================================================
Output: /home/isoft_lp/Github/Testtool/QuickStartGuide/output.xml
Log: /home/isoft_lp/Github/Testtool/QuickStartGuide/log.html
Report: /home/isoft_lp/Github/Testtool/QuickStartGuide/report.html
和python unittest很像啊。
同样可以使用各种命令行参数进行执行设置:
robot --log custom_log.html --name Custom_Name QuickStart.rst.
--log 指定了log名称,默认为log.html, --name 指定了测试名称,默认为测试数据文件名。 关于pybot参数说明,可以运行pybot --help查看。后续会对这些参数进行详细说明。
查看结果
上面执行的过程,可以看到生成了3个结果文件。这些文件链接在线可执行文件,但是执行示例会在本地创建结果文件。
- report.html 测试报告
- log.html 详细测试执行日志
- out.xml 机器可读的xml格式结果
测试用例
工作流测试
RF测试用例使用简单的表格语法创建。例如,下面有两个测试:
- 用户可以创建一个账户并登录
- 用户使用错误密码被拒绝登录
测试用例
Test Case | Action | Argument | Argument |
---|---|---|---|
User can create an account and log in | Create Valid User | fred | P4ssw0rd |
Attempt to Login with Credentials | fred | P4ssw0rd | |
Status Should Be | Logged In | ||
User cantnot log in with bad password | Create Valid User | betty | P4ssw0rd |
Attempt to Login with Credentials | betty | wrong | |
Status Should Be | Access Denied |
robot Framework 使用关键词驱动的方式,支持用自然语言来编写可以抓住动作和期望值的本质的测试。测试用例由关键词(通常在第二列)和它们可能的参数组成。
测试用例由关键字及其参数构成。语法要求其关键字和参数,以及设置及其值至少有两个空格或制表符分隔。通常建议使用4个空格分隔符更明确(不同设置下制表符不一样)。关于语法方面后续文章会再介绍。
高级测试
测试用例可以仅使用不具有位置参数的高级关键字来创建。这种风格允许使用完全自由的文本,甚至适用于非技术人员或其他项目利益者进行沟通。当使用验收测试驱动开发(ATDD)方法或其他任何变体和创建测试时尤为重要。
RF不强制编写测试用例的风格,它可以使用行为驱动开发(BDD)推荐的given-when-then格式的样例,如:
Test Case | Steps |
---|---|
User can change password | Given a user has a valid account |
when she changes her password | |
then she can log in with new password | |
and she cannot use the old password anymore |
这种测试用例或用户故事风格的测试用例类型很适合用于acceptance test-driven development(ATDD).在ATDD中接收测试在实现实际产品特性前编写并且反映了需求。
数据驱动测试用例
通常,几个测试用例相似,但他们的输入和输出数据略有不同。在这种情况下,数据驱动的测试允许改变测试数据,而不会重复工作流程。使用RF的[Template]将测试用例转为数据驱动测试,当template关键字执行时使用测试用例主体中的定义的数据:
Test Case | Action | Password | Expected error message |
---|---|---|---|
Too short password | Creating user with invalid password should fail | abCD5 | \${PWD INVALID LENGTH} |
Too long password | Creating user with invalid password should fail | abCD567890123 | \${PWD INVALID LENGTH} |
Password without lowercase letters | Creating user with invalid password should fail | 123DEFG | \${PWD INVALID CONTENT} |
Password without capital letters | Creating user with invalid passworld should fail | abcd56789 | \${PWD INVALID CONTENT} |
Password without numbers | Creating user with invalid password should fail | AbCdEfGh | \${PWD INVALID CONTENT} |
Password without special characters | Creating user with invalid password should fail | abCD56+ | \${PWD INVALID CONTENT} |
除了使用具有单独测试的[模板]设置以外,可以在设置表中使用“测试模块”设置一次,如本文中定义的setups和teardowns.这种情况下,为无效长度密码案例和其他无效案例创建单独的命令测试将变得很简单。然而,这需要将这些测试移动到独立的文件,否则模板将应用与此文件中其他的测试。
注意,上述示例中的错误信息是使用变量指定的。
关键词
用于测试用例创建的关键字来源主要有两个,重要测试库中的库关键字和可以使用与创建测试用例相同语法创建的用户关键字。
库关键字
所有最低级别的关键字都在使用标准编程语言(python或java)实现的测试库中定义。RF附带了一些测试库,可以分为标准库,外部库和自定义库。标准库和核心框架一起分发,并包括通用库,如OperatingSystem, Screenshot和Builtln,特别之处在于它的关键字可以自动使用。外部库,如用于web测试的selenium2Libary,必须单独安装。如果可用的测试库不够满足需求,可以很容易的创建自定义测试库。
为了能使用测试库提供的关键字,必须使用库设置导入关键字。本文中的测试需要标准OperatingSystem库(如删除文件)和定制LoginLibary(例如尝试常用凭据登陆)中的关键字。这两个库是在下面的设置表中导入的:
Settings Library OperatingSystem Library lib/LoginLibray.py
用户关键字
RF框架最强大的功能之一就是能够轻松地从其他关键字创建新的更高级别的关键字。创建这些所谓的用户定义关键字或用户关键字的语法类似于用于创建测试用例的语法。以前的测试用例中需要的更高级别的关键字都在此关键字表中创建:
Keyword | Action | Argument | Argument |
---|---|---|---|
Clear login database | Remove file | \${DATABASE FILE} | |
Create valid user | [Arguments] | \${username} | \${password} |
Create user | \${username} | \${username} | |
Status should be | SUCCESS | ||
Creating user with invalid password should fail | [Arguments] | \${password} | \${error} |
Create user | example | \${password} | |
Status should be | Creating user failed: \${error} | ||
Login | [Arguments] | \${username} | \${password} |
Attempt to login with credentials | \${username} | \${password} | |
Status should be | Logged In | ||
# Used by BDD test cases(this is a comment | |||
Given a user has a valid account | Create valid user | \${USERNAME} | \${PASSWORD} |
... | \${NEW PASSWORD} | ||
Status should be | SUCCESS | ||
Then she can log in with the new password | Login | \${USERNAME} | \${NEW PASSWORD} |
Status should be | Access Denied |
用户定义的关键字可以包括由其他用户定义或库关键字定义的操作。从这个例子可以看出,用户定义的关键字可以作为参数。它们也可以返回值,甚至包含FOR循环。现在,重要的是要知道用户定义的关键字使得测试创建者能够为常见的动作序列创建可重复使用的步骤。用户自定义的关键字可以帮助作者将测试尽可能的读取,并在不同的情况下使用适当的抽象级别。
变量
定义变量
变量是RF的组成部分,通常在测试中使用的任何可能发生变化的数据最好定义为变量。变量定义的语法很简单,如变量表所示:
Variable | Value |
---|---|
\${USERNAME} | janedoe |
\${PASSWORD} | J4n3D0e |
\${NEW PASSWORD} | e0D3n4j |
\${DATABASE FILE} | \\(\{TEMPDIR\}\\\){/}robotframework-quickstart-db.txt |
\${PWD INVALID LENGTH} | Password must be 7-12 characters long |
\${PWD INVALID CONTENT} | Password must be a combination of lowercase and uppercase letters and numbers |
变量还可以在命令行指定,如果测试需要在不同的环境中执行,这非常有用。比如:
robot --variable USERNAME:johndoe --variable PASSWORD:J0hnD0e QuickStart.rst
除了用户定义的变量外,还有一些内置的变量始终可用。这些变量包括上面例子使用的\\(\{TEMPDIR\}和\\){/}。
使用变量
变量可以在测试数据的大部分地方使用。它们最常用作关键字的参数,如以下测试用例所示。来自关键字的返回值也可以分配给变量,可以作为以后使用。例如,以下数据库包含user关键字将数据库内容设置为${database}变量,然后使用BuiltIn关键字Should Contain来验证内容。库和用户关键字都可以返回值。
测试用例
Test Case | Action | Argument | Argument | Argument |
---|---|---|---|---|
User status is stored in database | [Tags] | variables | database | |
Create Valid User | \${USERNAME} | \${PASSWORD} | ||
Database Should Contain | \${USERNAME} | \${PASSWORD} | Inactive | |
Login | \${USERNAME} | \${PASSWOED} | ||
Database Should Contain | \${USERNAME} | \${PASSWORD} | Active |
关键字
Keyword | Action | Argument | Argument | Argument |
---|---|---|---|---|
Database Should Contain | [Arguments] | \${username} | \${password} | \${status} |
\${database}= | Get File | \${DATABASE FILE} | ||
Should Contain | \${database} | \\(\{username\}/t\\){password}/t\${status} |
测试用例组织
测试套件
RF中测试用例的集合称为测试套件。每个包含测试用例的输入文件构成测试套件。执行本指南时,你可以在终端输出中看到测试套件QuickStart.该名称源自文件名,并且在报告和日志中可见。
可以通过将测试用例文件放入目录并将这些目录放入其他目录中来分层组织测试用例。所以这些目录自动创建更高级别的测试套件,从目录名称中获取其名称。由于测试套件只是文件和目录,他们被简单地放置到任何版本控制系统中。
Setups 和 teardowns
如果你希望在每次测试之前或之后执行某些关键字,请使用设置表中的setup 和 Teardown 设置。同样,可以使用“suite setup"和"suite Teardown”设置来指定整个测试套件之前和/或之后执行的关键字。
使用测试用例表中的[setup]和[Teardown],单个测试也可以进行自定义setup和teardown。这与早期使用数据驱动测试的[Template]相同。
在这个演示中,我们希望在执行开始之前确保数据库被清除,并且每次测试也会在之后清除:
Setting | Value |
---|---|
Test Setup | Clear Login Database |
Test Teardown |
RF允许将测试用例的标签设置为自由的元数据。可以在具有强制标签和默认标签设置的文件中为所有测试用例设置标签,如下表所示。还可以使用[Tags]设置为单个测试用例定义标签,如早期用户状态存储在数据库测试中。
Setting | Value | Value |
---|---|---|
Force Tags | quickstart | |
Default Tags | example | smoke |
当你在测试执行后查看报告时,您可以看到测试已经指定了与它们相关联的标签,还有基于标签生成的统计信息。标签可以用于许多其他目的,最重要的是选择要执行的测试的可能性之一。例如,可以尝试以下命令:
robot --include smoke QuickStart.rst
robot --exclude database QuickStart.rst
RF提供了一个用于使用python或Java创建测试库的API,远程库接口还允许使用其他编程语言。RF用户指南包含有关库API的详细说明。
例如,我们可以看一下本演示中使用的LoginLibrary测试库。该库位于lib/LoginLibary.py。下面是其代码,例如,关键字Create User如何映射到方法create_user的实际实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #!/usr/bin/env python3
# *-*coding=utf-8*-*
import os.path
import subprocess
import sys
class LoginLibrary(object):
def __init__(self):
self._sut_path = os.path.join(os.path.dirname(__file__),
'..', 'sut', 'login.py')
self._status = ''
def create_user(self, username, password):
self._run_command('create', username, password)
def change_password(self, username, old_pwd, new_pwd):
self._run_command('change-password', username, old_pwd, new_pwd)
def attempt_to_login_with_credentials(self, username, password):
self._run_command('login', username, password)
def status_should_be(self, excepted_status):
if expected_status != self._status:
raise AssertionError("Expected status to be '%s' but was '%s'."
% (expected_status, self._status))
def _run_command(self, command, *args):
command = [sys.executable, self._sut_path, command] + list(args)
process = subprocess.Popen(command, universal_newlines=True, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
self._status = process.communicate()[0].strip()
|
到此,相信大家对Robot Framework应该有了一个初步的认识了。