1 Tempest测试脚本的执行流程
Tempest的测试脚本一般针对同一资源的测试用例会被封装在一个类中,并写在单独的文件中。有些资源涉及的测试用例较多,也可将测试用例按功能划分,并封装在多个类内。以虚拟机创建的测试脚本为例:
class ServersTestJSON(base.BaseV2ComputeTest):
@classmethod def setup_credentials(cls):
@classmethod def setup_clients(cls):
@classmethod def resource_setup(cls):
@decorators.attr(type='smoke') @decorators.idempotent_id('1') def test_verify_server_details(self): pass
@decorators.attr(type='smoke') @decorators.idempotent_id('2') def test_list_servers(self): pass |
编写Tempest测试脚本前,首先要了解一下测试脚本的执行流程:
执行流程可分为以下几个部分:
- setUpClass()
- setUp()
- tearDown()
- tearDownClass()
cls.setUpClass()和cls.setUp()都是测试用例运行前的执行代码,区别在于cls.setUpClass()运行于所有测试用例之前,对每个测试用例类只执行一遍。而cls.setUp()是每个测试用例运行前都要执行的,一个类内如果含有3个测试用例,self.setUp()则要执行3次。
self.tearDown()和cls.tearDownClass()则用于测试用例执行后的处理,其区别同上。
1.1 测试用例运行前
cls.setUpClass()包含了以下四个函数:
- skip_check()
- setup_credentials()
- setup_client()
- resource_setup()
这四个函数分别负责跳过测试用例类、建立凭证信息、建立客户端别名,建立测试资源。cls.setUpClass()不允许自定义的测试用例类继承,也就是说使用者不可以改变建立测试用例类的流程。但其调用的cls.skip_check()等函数是可以被自定义的测试用例类继承的,并在继承的函数中完成相应功能,例如:可以在继承的cls.skip_check()中实现根据配置文件开关跳过测试用例。
1.2 测试用例运行后
cls.tearDownClass()包含了以下两个函数:
- resource_cleanup()
- credentials_cleanup()
cls.resource_cleanup()用于测试资源的清理,cls.credentials_cleanup()用于测试租户、用户等清理。同样,cls.tearDownClass()也不允许自定义的测试用例类继承。cls.resource_cleanup()和cls.credentials_cleanup()一般也不被继承。
2 Tempest脚本组成部分
class ServersTestJSON(base.BaseV2ComputeTest):
@classmethod def setup_credentials(cls):
@classmethod def setup_clients(cls): super(DeleteServersTestJSON, cls).setup_clients() cls.client = cls.servers_client
@classmethod def resource_setup(cls):
@decorators.attr(type='smoke') @decorators.idempotent_id('2') def test_list_servers(self): # The created server should be in the list of all servers body = self.client.list_servers() servers = body['servers'] found = [i for i in servers if i['id'] == self.server['id']] self.assertNotEmpty(found) |
测试用例脚本包括装饰器、客户端调用、断言语句等组成部分。测试脚本中调用客户端向OpenStack平台发送HTTP报文,来完成资源的增、删、改、查。通过断言语句判断是否符合预期结果,决定测试用例是否通过。
2.1 装饰器
- @decorators.idempotent_id()
为测试用例标记UUID,每个tempest测试用例都有一个唯一的UUID。在Linux下可使用uuidgen命令生成UUID。
- @decorators.attr()
标注测试用例类型,如“slow”、“smoke”、“negative”。
- @utils.services()
标记测试用例所需的服务。
- @testtools.skipIf()
符合条件时跳过用例。
- @testtools.skipUnless()
不符合条件时跳过用例。
2.2 调用客户端
test_list_servers中调用了self.client.list_servers()来获取虚拟机列表。在setup_clients()中可以看到self.client是cls.server_client的别名,一般这样做是为了使客户端的名字变简短,编写代码更方便。
在tempest/lib/services文件夹中可以找到对应的client,如下:
class ServersClient(base_compute_client.BaseComputeClient): def create_server(self, **kwargs): ...
def update_server(self, server_id, **kwargs): ...
def show_server(self, server_id): ...
def delete_server(self, server_id): ... def list_servers(self, detail=False, **params): url = 'servers' schema = self.get_schema(self.schema_versions_info) if detail: url += '/detail' _schema = schema.list_servers_detail else: _schema = schema.list_servers if params: url += '?%s' % urllib.urlencode(params) resp, body = self.get(url) body = json.loads(body) self.validate_response(_schema, resp, body) return rest_client.ResponseBody(resp, body) |
从代码中可以看出,客户端对应一种资源,包含该资源的增、删、改、查等操作。self.client.list()中主要做了以下几个操作:
- 整理URL
- 发送GET请求
- 检查响应报文 (虚拟机管理的服务Nova涉及micro version的问题,其他服务的客户端可能没有此项)
该函数是对资源的查操作,如果是增操作则有可能发送POST请求,请求的参数与OpenStack API对应,可查阅OpenStack API文档。
客户端是带有凭证信息的,在每次调用客户端发送请求前,客户端都会检查是否存在token的缓存,如果没有则会使用凭证信息请求token,之后再发送报文。
客户端的凭证初始化由相应的manager完成。
如果测试用例中声明了类属性credential=[‘admin’, ‘primary’, ‘alt’],则会有os_admin、os_primary、os_alt这三种manager,分别拥有admin和两种普通权限。例子中的客户端实际由os_primary得来,所以是以普通用户为凭证的。
2.3 断言
断言是指有条件地在程序代码中触发异常,用于检查测试时是否符合预期结果。在tempest脚本编写过程中,常用的断言有如下几种:
断言 |
功能 |
assertEqual(a, b) |
判断a是否与预期结果b相等 |
assertNotEqual(a, b) |
判断a是否与b不相等 |
assertGreater(a, b) |
判断a是否大于b |
assertLess(a, b) |
判断a是否小于b |
assertIn(a, b) |
判断a是否在预期结果b中 |
assertNotIn(a, b) |
判断a是否不在b中 |
assertRaise() |
判断是否抛出指定异常 |
本篇文章介绍了tempest测试用例执行流程和常用测试例组成部分,后续文章将介绍配置、实际操作和代码级分析。