美文网首页iT程序人生
测试框架实践--TestFixture

测试框架实践--TestFixture

作者: 疯狂的程序猿丶 | 来源:发表于2018-11-13 16:35 被阅读7次

    一个测试类,通常有多个测试方法,有时候一个或多个测试方法都需要某些共用的”数据“, 比如说都要访问某个数据库的某张表,比如说都需要起浏览器,都需要调用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()只会执行一次,即使这个测试类有多个测试函数。

    我们在实现这个之前,先看下上次我们实现并发时,真正执行一个测试函数的代码块, 它的代码:
    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方法了。

    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,当然你得做好线程安全。

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

    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.这样第一层次的并发,是基于测试类的,然后针对每一个测试类,我再进行并发。

    具体代码如下:

    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)
    为了验证正确性,我把我们的测试类和方法改进如下:

    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 #关注iTesting,与万人测试团一起成长
    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
    跑一下看看:


    123.png

    可以看到,cls.status这个共享数据,成功被测试函数接收到了。 setUpClass(我这里对应before_class)也成功运行, 且只运行了一次。

    毫无破绽:)

    到此为止,我已经实现了一个测试框架的绝大数功能,下一步,就要改造我的log还有接收用户参数了,敬请期待。

    ——————————————————————————————————————

    最后给大家推荐一个学习资料分享群(574253227),里面大牛已经为我们整理好了许多的学习资料,有自动化,接口,性能等等的学习资料!

    相关文章

      网友评论

        本文标题:测试框架实践--TestFixture

        本文链接:https://www.haomeiwen.com/subject/mvylfqtx.html