测试的 setup(环境创建)和 teardown (清除),是每个自动化测试框架都会涉及到的概念。简单的说, setup 是测试一个用例(或者套件)前要做的事情, teardown 是测试后要做的事情。其实,任何测试,包括手工测试都会涉及到 setup 和 teardown 。
比如,我们有一个 web 系统,测试登录功能的时候,需要先注册1个用户,用这个用户验证登录功能。那么对于测试登录功能的套件(或者用例)来说,前面先注册好一个用户的操作,就是 setup 。而是否要 teardown ,主要看这个用例执行后的结果是否会影响下面要执行的用例。比如,我们执行了上面用户登录的测试后,,如果要测试系统的统计功能,统计当前有多少个用户登录,其中的一个用例就是,当没有用户登录的时候,显示登录数量为0。这个时候就需要前面的用例执行完后,必须 teardown ,否则会影响后面用例的执行。由于人具有较高的智能判断能力,在人工执行用例的时候,会记忆或者判断出当前的系统的状态是否满足 测试某个用例的条件。所以测试用例书写的时候,往往并没有清除的写出执行前后需要做什么 setup、teardown。而自动化测试软件就不一样了,它必须明确每一个测试套件(用例)执行时的状态,否则一旦用例数量比较大的时候,就经常会出现由于执行前环境的不同而导致测试执行异常。有的时候不同的执行用例的顺序,会导致同样的测试用例和被测系统,这次执行成功,下次执行失败。
在 RF 中,每个测试套件目录、测试套件文件、测试用例都可以有自己的 setup 和 teardown ,所有的 setup 和 teardown 操作都是由一个关键字语句构成的。
测试用例的 setup、teardown
- 写在测试用例的表的配置项中
*** Test Cases ***
测试1
[Setup] log to console \n *** case st setup ***
log to console 测试用例主体部分
[Teardown] log to console \n *** case st teardown ***
这里有一个测试用例 Test Cases 叫 测试1 ,它的配置项就是我们用方括号括起来的一个是 [Setup] 一个是 [Teardown]。
这边有个例子:
*** Test Cases ***
测试1
[Documentation] 测试初始化、清除
[Setup] log to console \n *** 测试用例1 setup ****
log to console 测试用例1主体部分
[Teardown] log to console \n *** 测试用例 1 teardown ****
测试2
log to console 测试用例2主体部分
测试3
log to console 测试用例3主体部分
这边测试用例有测试1、测试2、测试3,三个测试用例,在测试1里面有方括号括起来的 [Setup]、[Teardown]。这个就代表测试用例1的 [Setup]和[Teardown] ,这边没有什么具体的内容,我的 [Setup] 和 [Teardown] 只是打了一些 log 我们执行一下看一下它的结果。
我们可以看到首先打印了测试1的 Setup 接下来是用例1的主体部分,然后是他的 Teardown 这是测试用例1打印的所有的 log ,在执行主体部分之前是 Setup 做的操作,主体部分执行完之后是 teardown 的工作,其它的两个测试用例测试用例2和3只有主体部分,因为他没有 [Setup] 和 [Teardown] 所以只执行主体部分,这个比较简单 [Setup] 和 [Teardown] 一般做一些初始化清除的有实质内容的工作,我们这里为了演示只是打印 log,我们看下 log 看看执行 log 上的内容,也会记录初始化与清除的工作的。
这个是测试用例的 [Setup] 和 [Teardown] 大家理解一下,接下来看下测试套件文件的
测试套件文件的Setup和Teardown
除了测试用例以外,测试套件也有初始化与清除,有的人会想测试用例中有不就行了吗,为什么测试套件里面也要有初始化与清除呢?大家考虑这样一种情况,因为我们有的情况其实针对一个测试套件里面所有的用例都需要做的一个操作,比如说我有一个用户登录的功能,里面有10个用例,这些用例的初始化都是要创建一个用户,举个例子:
这里有一个登陆用户的用户名和密码,用户名就是abc
,密码就是123
,有这样一个用户,这边用例是创建一个用户跟之前的用户abc
密码123
有关联关系,比如创建一个test suite1
里面t1里面跟已存在的用户用户名是一样的abc
密码不一样12
,然后test case2
用户名不一样密码是一样的,testcase3
用户名ab
和密码12
都不一样。
如果有这样一个测试套件文件,这里面的测试用例它都需要存在一个用户名是abc
密码是123
用户,第一个用例是创建一个和用户名一样密码不一样的用户,第二是用户名不一样密码一样,第三用户名密码都不一样,那对于这种测试套件里面的测试用例他是不是共用一个初始化条件就是有一个用户名是abc
密码是123
的用户,如果我们只在每一个测试case里面去定义用户名密码,十个用例我要把用户名为abc
密码123
的用户创建十次,所以因为这个原因我们在test suite1
的初始化里面就创建了这样一个abc
的用户,我在下面case执行的时候就不需要在创建了,所以他们共用一套初始化的环境,我们不需要在每个初始化的用户里面都创建这样一个用户,我们只需要在进入测试套件整个测试套件文件执行之前创建一个用户,在所有的测试套件里面呢每个用例执行完了之后再把它删掉这样的话就可以了,有的人会想既然像之前这种情况,我直接在t1
里面创建一个用户名为abc
密码为123
的用户,不删掉,给后面的2,3使用这样可以吗??这样是不可以的,因为如果前面创建失败或者测试用例失败, 那后面的就没有初始化条件测试就不对了,还有一种情况你怎么知道我每次执行会选择所有的用例呢?如果我先执行后面的测试用例最后在执行t1
或者我根本就不执行t1
会有什么问题呢,那我的初始化环境就没有了,所以这里给大家强调测试用例之间一定不要有相互依赖关系因为你每次选择测试用例都是不一样的比如有冒烟测试。顺序和数量都是不一样的所以不能把某个 case 作为其他 case 的依赖,所以我们不能这样做,这边就要用到测试套件文件的 setup、teardown 这是为什么需要他,知道了原因之后我们来看,测试套件文件的 setup、teardown 。
测试套件有两种类型的 Setup 和 Teardown,一个是 Suite setup/Teardown,一个是 Test setup/Teardown。其中前者的(suite的)是进入这个 suite 执行用例前必须执行且只执行一次。而后者是,如果 suite 内的用例本身没有 setup/Teardown ,才执行缺省 setup/Teardown 。后者会被包含用例的 setup/Teardown 所取代。测试套件文件的 setup、teardown 是写在文件的 Settings 表中的。
我们先看第一个 Suite setup/Teardown 例子:
*** Settings ***
Suite Setup log to console \n --- Suite st2 Setup ---
Suite Teardown log to console \n --- Suite st2 Teardown ---
*** Test Cases ***
测试1
[Setup] log to console \n *** case 测试1 setup ****
log to console 测试用例主体部分 11
[Teardown] log to console \n *** case 测试1 teardown ****
测试2
log to console 测试用例主体部分22
测试3
log to console 测试用例主体部分33
首先他是放在测试套件的 Settings 表里面,这个测试套件文件有三个测试用例第一个测试用例有自己的 setup Teardown ,第二个第三个没有,而这个 Suite setup/Teardown 执行顺序是进入测试套件之前先执行 Suite Setup ,所有的用例执行完了之后再执行 Suite Teardown 我们执行一下。
进入到测试 Suite 的之后就执行它的 Suite Setup,然后是测试用例主体的1、2、3部分,全部执行完了之后再执行 Suite 的 Teardown。大家看到没,他是包在测试用例的头和尾之间的。
下面看一下 Test Setup\Teardown
*** Settings ***
Suite Setup log to console \n --- Suite st Setup ---
Suite Teardown log to console \n --- Suite st Teardown ---
Test Setup log to console \n --- Test st Default Setup ---
Test Teardown log to console \n --- Test st Default Teardown ---
*** Test Cases ***
测试1
[Setup] log to console \n *** case 1 setup ****
log to console 测试用例主体部分11
[Teardown] log to console \n *** case 1 teardown ****
测试2
log to console 测试用例主体部分22
测试3
log to console 测试用例主体部分33
我们除了刚才的 suite setup 之后我们又加了两个 Test Setup 和 Test Teardown 仍然放在 Settings 表里面的,我们刚说了 Test setup/Teardown 如果用例本事没有 setup 和 Teardown 我们才用它的,我们看一下这个测试套件文件里面有三个用例,第一个用例有自己的 setup和Teardown 他还会用 Test Setup 和 Test Setup Teardown 吗,如果他有的话它就会用自己的,测试用例2和3他们没有自己的测试套件初始化和清除那么他就会用 Test Setup\Teardown 作为它的 Default 的 case 的 setup 和 teardown ,运行截图:
这个是测试套件文件的 setup 和 Teardown 除了测试套件的文件还有测试套件的目录呢,测试套件可以是目录也可以是文件,测试套件的文件又可以包含子的套件目录也可以包含子的文件,比如我们有一些组合目录登录功能、注册功能都输入用户管理功能等等,就是这种一层层组合的,可以加很多目录出来,我们测试套件的目录它也可以有初始化和清除,有没有觉得奇怪啊,测试套件文件它对应一个文件初始化清除就放在文件的Settings 表里面,这个很容易理解,那么测试套件目录他是一个目录它的初始化清除对应的语句要放在那里呢?大家来看一下。
测试套件目录的 setup Teardown
我们 python 里面都有 package 都有对应的 __init__.py
文件,那么 robot 里面测试套件
目录的 setup 和 Teardown 它放在他目录的配置文件 __init__
这个 Settings 表里面,他可以是 __init__.txt
或者 __init.robot__
如果这个文件存在了他就对应这个目录的配置文件,我们把它放在这些文件的 settings 表里面。 这个和 python 是一样的,而且他们 settings 里面的 setup 和 Teardown 和我们测试套件文件也非常类似。他也分两种类型的一种是 Suite ,一种是 Test 大家理解一下.
- 两种类型
Suite setup/Teardown
进入和退出这个suite执行用例前后必须执行且只分别执行一次Test setup/teardown
如果 suite 内的用例、或者子套件本身没有 setup/teardown ,才执行
我这里有个 suit1 有个 st1.robot 和 st2.robot 如果想给 suit1 做一个初始化清除的文件,那么就需要创建一个 init.robot 大家看一下
__init__.robot
里面打印的 log 都叫 Suite big Setup 以及 Test big Default两种类型(test和suite),这是测试套件suite1的初始化与清除,这里面有个 St1.robot
*** Settings ***
Suite Setup log to console \n --- Suite little Setup ---
Suite Teardown log to console \n --- Suite little Teardown ---
Test Setup log to console \n --- Test little Default Setup ---
Test Teardown log to console \n --- Test little Default Teardown ---
*** Test Cases ***
测试1
[Setup] log to console \n *** 测试用例1 setup ****
log to console 测试用例1 主体部分
[Teardown] log to console \n *** 测试用例1 teardown ****
测试2
log to console 测试用例2 主体部分
St1 里面又有自己的 Suite Setup/Teardown 和 Test Setup/Teardown,st1 又有测试用例1和测试用例2,测试用例1有自己的测试用例的 setup 和 Teardown ,还有一个St2.robot
*** Test Cases ***
测试3
[Setup] log to console \n *** 测试用例3 setup ****
log to console 测试用例3主体部分
[Teardown] log to console \n *** 测试用例3 teardown ****
测试4
log to console 测试用例4主体部分
St2.robot 没有任何的 Suite Setup/Teardown 但是测试用例3有他自己的这个 setup 和 Teardown用例4就什么都没有,我们执行下看看,它会打印出什么东西出来,执行之前我们要想一下怎么执行呢?这是一个套件套件怎么执行?直接用 robot 直接执行 suit1就可以了,整个 suit1 有两个测试用例的文件 st1 和 st2 对应的测试用例一个是测试1测试2,另一个是测试3和测试4,那我看下他们执行的结果。运行结果有点长,截图一次截不了我就把结果复制了
E:\tmp\rf1>robot suite1
==============================================================================
Suite1
==============================================================================
--- Suite big Setup ---
Suite1.St1
==============================================================================
--- Suite little Setup ---
测试1
*** 测试用例1 setup ****
.测试用例1 主体部分
.
*** 测试用例1 teardown ****
测试1 | PASS |
------------------------------------------------------------------------------
测试2
--- Test little Default Setup ---
.测试用例2 主体部分
.
--- Test little Default Teardown ---
测试2 | PASS |
------------------------------------------------------------------------------
--- Suite little Teardown ---
Suite1.St1 | PASS |
2 critical tests, 2 passed, 0 failed
2 tests total, 2 passed, 0 failed
==============================================================================
Suite1.St2
==============================================================================
测试3
*** 测试用例3 setup ****
.测试用例3主体部分
.
*** 测试用例3 teardown ****
测试3 | PASS |
------------------------------------------------------------------------------
测试4
--- Test big Default Setup ---
.测试用例4主体部分
.
--- Test big Default Teardown ---
测试4 | PASS |
------------------------------------------------------------------------------
Suite1.St2 | PASS |
2 critical tests, 2 passed, 0 failed
2 tests total, 2 passed, 0 failed
==============================================================================
--- Suite big Teardown ---
Suite1 | PASS |
4 critical tests, 4 passed, 0 failed
4 tests total, 4 passed, 0 failed
==============================================================================
Output: E:\tmp\rf1\output.xml
Log: E:\tmp\rf1\log.html
Report: E:\tmp\rf1\report.html
E:\tmp\rf1>
suite1 有两个测试用例的文件 st1 和 st2 对应的测试用例测试1,测试2,测试3,测试4,4个测试文件 ,看下执行的结果:首先进入 suite1的话他会先执行__init__
里面的 Suite Setup log to console |n---Suite big Setup ---
和Suite Teardown log to console |n--- Suite big Teardown ---
我们整个测试套件执行最外层开头和结尾就应该是|n---Suite big Setup ---
和|n--- Suite big Teardown ---
。
接下来进来之后会执行两个测试套件的文件,一个是 st1 一个是 st2 ,进入st1 的时候要执行测试用例1之前,他是不是有Suite Setup log to console |n ---Suite little Setup --- Suite Teardown log to console |n --- Suite little Teardown ---
这个 Suite Setup/Teard 是不是要包在测试用例1和测试用例2外面,因为我前面的Setup是在最外层,这个里面的应该包在1和2外面,应该会有---Suite little Setup ---
和--- Suite little Teardown ---
包在测试1和测试2之间
这个是包在用例1和2外面的
执行完这个 Setup 之后他才执行自己内部的 setup 和 teardow 首先用例1又有自己的|n *** 测试用例1 setup ***
和|n *** 测试用例1 Teardown ***
那么我们用例1在执行主体之前,大家看下主体部分的上和下分别有个测试用例1的|n *** 测试用例1 setup ***
和|n *** 测试用例1 Teardown ***
测试用例2没有 steup 和 Teardown 那它是用
st1.robot 中的 Setup teardown 还是
__init__
中的Setup teardown
,应该用离它近的大家记住就近原则,所以测试2应该包在两边的是|n --- Test little Default Setup ---
和|n --- Test little Default Teardown ---
这是测试用例1和2//,接下来看一下 st2.robot 里面没有 Setup 和Teardown,但是测试3有自己的Setup和Teardown所以3**的外面应该包着\n *** 测试用例3 setup ***
和\n *** 测试用例3 teardown ***
接着看用例4自己没有Setup和Teardown他所在的st2文件也没有Setup和Teardown,他就用到了最外层的|n--- Test big Default Setup ---
和|n--- Test big Default Teardown ---
我们把suite1里面的4个测试用例Setup和Teardown.的顺序过了一遍,从过的顺序我们了解他们遵循的一个原则由内向外优先级递减,如果自己有的话就尽量用自己的,没有的话就往上找
总结:
我们__init_
里面的Suite Setup Teardown他只执行一次Test Setup Teardown是根据需要的,如果他没有的话就会被多次复用,如果每个本身都有的话他可能一次都不会被用到,Test Setup Teardown每个用例如果没有自己Default (缺省)就会用Test Setup Teardown,如果没个用例都有就不会用到Test Setup Teardown被用的次数是不固定的。
刚才我们执行用例用的命令是:
robot suite1
执行了整个suite1
如果我们只想执行其中的一个套件,比如我就想执行suite1
下st1.robot
该怎么执行呢,这样写是不行的
robot suite1\st1.robot
虽然我运行也是执行了,
执行之后我们看下他的
log
,最上层的log是|n ---Suite little Setup ---
开始的,|n ---Suite little Setup ---
是在st1
的Suite Setup
但是他最上层的__init__
没有执行,因为我直接就进入到st1
去执行了,这种情况下比如说我最上层有一些初始化可能就走不到了,这样是不行的因为robot
关注的是路径的最后部分,这里如果想要执行应该这样写我们要执行那个suite
就--suite
比如st1
我们最终是suite1
里面的,就是
robot --suite st1 suite1
这样就执行到了:
这个参数是告诉robot目标参数是 suite1 里面挑了一个 st1,是这种目的
如果有多个套件要执行就是
`robot --suite st1 --suite st2 suite1
这样四个用例就都执行了。
--suite
指定的就是执行的是那个子套件,如果我就只要执行测试用例1就这样写
robot --test 测试1 suite1
表示:robot suite1 里面的某一个测试用例