前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >测试框架实践--TestFixture

测试框架实践--TestFixture

作者头像
Criss@陈磊
发布2019-08-01 19:18:55
3720
发布2019-08-01 19:18:55
举报
文章被收录于专栏:测试技术圈测试技术圈

一个测试类,通常有多个测试方法,有时候一个或多个测试方法都需要某些共用的”数据“, 比如说都要访问某个数据库的某张表,比如说都需要起浏览器,都需要调用post方法等。 这个时候每个测试用例单独写就显得很多余,TestFixture就应运而生。

我们先来看下Test Fixture的定义:

A test fixture represents the preparation needed to perform one or more tests, and any associate cleanup actions. This may involve, for example, creating temporary or proxy databases, directories, or starting a server process.

由此可见,Test Fixture用在测试方法前,或者测试方法后,主要功能是提供一些测试需要用的装置,这些装置可以是数据,可以是环境配置也可以是一个运行前状态。

Fixture有下面两种: 1.setup(), teardown()的方式,分别在每个测试方法执行前后执行。 2.setUpClass(), tearDownClass()的方式,分别在每个测试类执行前后执行, setUpClass()和tearDownClass()只会执行一次,即使这个测试类有多个测试函数。

我们在实现这个之前,先看下上次我们实现并发时,真正执行一个测试函数的代码块, 它的代码:

代码语言:javascript
复制
 1def f(case):
 2    name, func, value = case
 3    try:
 4        if value:
 5            func.__call__(name, *value)
 6        else:
 7            func.__call__(name)
 8    except:
 9        # traceback.print_exc()
10        cases_run_fail.append(name)
11    else:
12        cases_run_success.append(name)
13    return cases_run_fail, cases_run_success

这个代码块是针对每一个测试函数的,那么我们多线程运行时,每个测试函数都会执行这段代码,这样就好办了,直接把setup和teardown加进来就能实现每个测试函数都执行setup和teardown方法了。

代码语言:javascript
复制
 1def f(case):
 2    cls, name, func, value = case
 3    try:
 4        # Run setUP method for each test method.
 5        #看这里
 6        getattr(cls, "setUp").__call__(cls) 
 7
 8        if value:
 9            func.__call__(name, *value)
10        else:
11            func.__call__(name)
12
13        #看这里    
14        # Run tearDown method for each test method.
15        getattr(cls, "tearDown").__call__(cls)
16    except:
17        # traceback.print_exc()
18        cases_run_fail.append(name)
19    else:
20        cases_run_success.append(name)
21    return cases_run_fail, cases_run_success

可以看到这个函数传入的参数也改变了,case的值里加入了cls这个类。要达成这个效果, 相当于如何根据测试方法找到所属的测试类,利用inspect模块很简单的就拿到了,当然你也可以用__name__拿到函数名。

setup和teardown这两个方法每个测试用例都会执行,看到这里想明白了吗?这就意味着如果你在这里做初始化浏览器的操作,那么这个框架就可以做UI自动化,如果你做的是HTTP的get或者post的操作,那么这个框架也就是API接口框架。

setup和teardown实现了。我们再来看下setUpClass, tearDownClass的实现。那么我是怎么共享线程间的变量呢?

常规情况下,我们可以用数据持久化的方式实现,具体来说,就是每个测试函数执行时候先去找一个文件,这个文件在就不再执行setUpClass,当然你得做好线程安全。

大家还记得我的多线程是怎么实现的呢?

代码语言:javascript
复制
1#多线程部分代码
2with ThreadPool(number_of_threads) as p:
3    p.map(f, cases_to_run)
4p.close()
5p.join()

对于每一个线程,都去调用f函数,这个函数就是上方实现了每个函数setup和teardown的f。

现在好了,我们用map可以不关心这些,直接嵌套实现:

1.我把所有的用例重新组织,形成一种特殊的数据结构,具体来说,就是每个测试类和属于这个测试类的所有函数, 以如下方式组织(cls, [cls.method1, cls.method2]),最终所有的测试类,在放到一个列表对象里。 2.这样第一层次的并发,是基于测试类的,然后针对每一个测试类,我再进行并发。

具体代码如下:

代码语言:javascript
复制
 1#部分代码
 2def run(case):
 3    #cls是测试类
 4    cls = case[0]
 5    #func_pack是测试函数及所有参数
 6    func_pack = case[1] 
 7
 8    #实现setUPClass
 9    #到这一层只是类并发,真正的测试函数还没有并发。
10    #setUPClass应该做到测试类有设置就执行,否则就不执行。
11    handle_before_class_fixture(cls)
12
13    p = ThreadPool(number_of_threads)
14    #真正的测试函数并发
15    #这个func_run就相当于我们之前的f。
16    p.map(func_run, func_pack)
17    p.close()
18    p.join()
19
20    #实现tearDownClass
21    handle__after_class_fixture(cls)

为了验证正确性,我把我们的测试类和方法改进如下:

代码语言:javascript
复制
 1@TestClass()
 2class TestSumData:
 3    @BeforeClass()
 4    def before_class(cls):
 5        print("haha")
 6        cls.status = 1
 7    def setUp(self):
 8        print("Now starting")
 9    @data_provider([(1, 2, 3), (4, 5, 9)])
10    @Test()
11    def test_sum_data(self, x, y, z):
12        print('Case {0} are running with data {1} -- thread id {2}'.format(
13            self, (x, y, z), current_process()))
14        print(self.status)
15        assert SumData().sum_data(x, y) == z
16    @Test(enabled=True)
17    def test_sum_data2(self):
18        print('Case {0} are running with data {1} -- thread id {2}'.format(
19            self, None , current_process()))
20        print(self.status)
21        assert SumData().sum_data(4, 5) == 7
22    def tearDown(self):
23        print("Now finished")
24    @AfterClass()
25    def after_class(cls):
26        cls.status =0
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-04-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 质问 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
日志服务
日志服务(Cloud Log Service,CLS)是腾讯云提供的一站式日志服务平台,提供了从日志采集、日志存储到日志检索,图表分析、监控告警、日志投递等多项服务,协助用户通过日志来解决业务运维、服务监控、日志审计等场景问题。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档