前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >框架化你的代码

框架化你的代码

作者头像
赵云龙龙
发布2021-04-23 11:14:05
5230
发布2021-04-23 11:14:05
举报
文章被收录于专栏:python爱好部落

前面讲了如何不写代码可以实现自动化。 但是录制的代码很杂乱且冗余,可读性和维护性太差。 下面来介绍如何搭建自动化框架,将录制的代码整理,让其变得简洁。 python市面见得多的是以下两种框架。 1.unittest

(1)测试类必须继承unittest.TestCase

(2)测试函数必须以”test_”开头

(3)测试类必须有unittest.main()方法

2.pytest

(1)测试文件的文件名必须以”test_”开头,或者以”_test”结尾

(2)测试类命名必须以”Test”开头

(3)测试函数名必须以”test”开头

(4)测试类里面不能使用”init”方法

总结:pytest是基于unittest衍生出来的新的测试框架,使用起来相对于unittest来说更简单、效率来说更高,pytest兼容unittest测试用例,但是反过来unittest不兼容pytest,所以说pytest的容错性更好一些!在使用交互逻辑上面pytest比unittest更全一些!

unittest是python自带的测试库,自我感觉的话,如果对python只是了解基础知识,学unittest框架相对于来说要好理解些,unittest框架也完全可以实现市场上大部分的业务测试!建议可以先了解下unittest框架,然后在学pytest框架,可以更好的去感受一下两个框架的优缺点。

unittest是python内置的用于测试代码的模块,无需安装, 使用简单方便 unittest工作原理 写好一个完整的TestCase 多个TestCase 由TestLoder被加载到TestSuite里面, TestSuite也可以嵌套TestSuite 由TextTestRunner来执行TestSuite,测试的结果保存在TextTestResult中 TestFixture指的是环境准备和恢复

unittest中最核心的部分是:TestFixture、TestCase、TestSuite、TestRunner

Test Fixture

用于测试环境的准备和恢复还原, 一般用到下面几个函数。

  • setUp():准备环境,执行每个测试用例的前置条件
  • tearDown():环境还原,执行每个测试用例的后置条件
  • setUpClass():必须使用@classmethod装饰器,所有case执行的前置条件,只运行一次
  • tearDownClass():必须使用@classmethod装饰器,所有case运行完后只运行一次
Test Case
  • 参数verbosity可以控制错误报告的详细程度:默认为1。0,表示不输出每一个用例的执行结果;2表示详细的执行报告结果。
  • Verbosity=1情况下成功是 .,失败是 F,出错是 E,跳过是 S
  • 测试的执行跟方法的顺序没有关系, 默认按字母顺序
  • 每个测试方法均以 test 开头
  • Verbosity=2情况下会打印测试的注释

被测代码,demo.py文件

代码语言:javascript
复制
#!/usr/bin/python
# -*- coding: utf-8 -*-

def add(a, b):
    return a+b

def minus(a, b):
    return a-b

测试case, test_demo_class.py文件

代码语言:javascript
复制
#!/usr/bin/python
# -*- coding: utf-8 -*-

import unittest
from demo import add, minus

class TestDemo(unittest.TestCase):
    """Test mathfuc.py"""

    @classmethod
    def setUpClass(cls):
        print ("this setupclass() method only called once.\n")

    @classmethod
    def tearDownClass(cls):
        print ("this teardownclass() method only called once too.\n")

    def setUp(self):
        print ("do something before test : prepare environment.\n")

    def tearDown(self):
        print ("do something after test : clean up.\n")

    def test_add(self):
        """Test method add(a, b)"""
        self.assertEqual(3, add(1, 2))
        self.assertNotEqual(3, add(2, 2))

    def test_minus(self):
        """Test method minus(a, b)"""
        self.assertEqual(1, minus(3, 2))
        self.assertNotEqual(1, minus(3, 2))

    @unittest.skip("do't run as not ready")
    def test_minus_with_skip(self):
        """Test method minus(a, b)"""
        self.assertEqual(1, minus(3, 2))
        self.assertNotEqual(1, minus(3, 2))

if __name__ == '__main__':
    # verbosity=*:默认是1;设为0,则不输出每一个用例的执行结果;2-输出详细的执行结果
    unittest.main(verbosity=1)

Test Suite
  • 一般通过addTest()或者addTests()向suite中添加。case的执行顺序与添加到Suite中的顺序是一致的
  • @unittest.skip()装饰器跳过某个case (1)skip():无条件跳过 @unittest.skip("i don't want to run this case. ") (2)skipIf(condition,reason):如果condition为true,则 skip @unittest.skipIf(condition,reason) (3)skipUnless(condition,reason):如果condition为False,则skip @unittest.skipUnless(condition,reason)
Test Loder
  • TestLoadder用来加载TestCase到TestSuite中。
  • loadTestsFrom*()方法从各个地方寻找testcase,创建实例,然后addTestSuite,再返回一个TestSuite实例
  • defaultTestLoader() 与 TestLoader()功能差不多,复用原有实例

unittest.TestLoader().loadTestsFromTestCase(testCaseClass) unittest.TestLoader().loadTestsFromModule(module) unittest.TestLoader().loadTestsFromName(name,module=None) unittest.TestLoader().loadTestsFromNames(names,module=None) unittest.TestLoader().discover()

实例如下, test_demo_module.py文件

代码语言:javascript
复制
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
import HTMLReport
import unittest
import test_demo_class
from test_demo_class import TestDemo

if __name__ == '__main__':
    paras = sys.argv[1:]
    args = paras[0]
    report = paras[1]

    suite = unittest.TestSuite()
    if args == 'test':
        tests = [TestDemo("test_minus"), TestDemo("test_add"), TestDemo("test_minus_with_skip")]
        suite.addTests(tests)
    elif args == 'tests':
        suite.addTest(TestDemo("test_minus"))
        suite.addTest(TestDemo("test_add"))
        suite.addTest(TestDemo("test_minus_with_skip"))
    elif args == 'class':
        suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestDemo))
    elif args == 'module':
        suite.addTests(unittest.TestLoader().loadTestsFromModule(test_demo_class))
    elif args == 'mix':
        suite.addTests(unittest.TestLoader().loadTestsFromName('test_demo_class.TestDemo.test_minus'))
    elif args == 'mixs':
        suite.addTests(unittest.TestLoader().loadTestsFromNames(['test_demo_class.TestDemo.test_minus', 'test_demo_class.TestDemo', 'test_demo_class']))
    elif args == 'discover':
        suite.addTests(unittest.TestLoader().discover('.', 'test_*.py', top_level_dir=None))

    if report == 'terminal':
        runner = unittest.TextTestRunner(verbosity=1)
        runner.run(suite)
    elif report == 'txt':
        with open('ut_log.txt', 'a') as fp:
            runner = unittest.TextTestRunner(stream=fp, verbosity=1)
            runner.run(suite)
    elif report == 'html':
        runner = HTMLReport.TestRunner(report_file_name='test',
                               output_path='report',
                               title='测试报告',
                               description='测试描述',
                               sequential_execution=True
                               )
        runner.run(suite)


Testing Report
  • 终端报告:如上terminal 分支
  • TXT报告:如上txt 分支,当前目录会生成ut_log.txt文件
  • HTML 报告:如上html 分支,终端上打印运行信息同时会在当前目录生成report文件夹, 文件夹下有test.htmltest.log文件

例子如下: 创建一个函数集mathfunc.py

代码语言:javascript
复制
def add(a,b):
    return a+b
 
def minus(a, b):
    return a-b
 
def multi(a, b):
    return a*b
 
def divide(a, b):
   return a/b

接下来是为这些方法写的一个测试: test_mathfunc.py

代码语言:javascript
复制
import unittest
from mathfunc import *
 
class TestMathFunc(unittest.TestCase):
 
    def setUp(self):
        print "do something befor test.prepare environment"
 
    def tearDown(self):
        print "do something after test.Clean up"
 
    def test_add(self):
        self.assertEqual(3,add(1,2))
        self.assertNotEqual(3,add(2,2))
 
    @unittest.skip("i don't want to run this case")
    def test_minus(self):
        self.assertEqual(1,minus(3,2))
 
    def test_multi(self):
        self.assertEqual(6,multi(2,3))
 
    def test_divide(self):
        self.assertEqual(2,divide(6,3))
        self.assertEqual(2.5,divide(5,2))
 
if __name__ == '__main__':
    unittest.main()

组织TestSuite

上面的代码演示了如何编写一个简单的测试,下面说一下怎么控制用例执行的顺序。我们就要用到TestCase,添加到TestCaseDE中的case是会按照添加的顺序执行的。

来个例子:

在文件夹中再新建一个文件。test_suite.py

代码语言:javascript
复制
# -*- coding: utf-8 -*-
 
import unittest
from test_mathfunc import TestMathFunc
 
if __name__ == '__main__':
    suite = unittest.TestSuite()
 
    tests = [TestMathFunc("test_add"), TestMathFunc("test_minus"), TestMathFunc("test_divide")]
    suite.addTests(tests)
 
    runner = unittest.TextTestRunner(verbosity=2)
如何控制用例执行顺序

在unittest中,用例是以test开头的方法定义的,默认执行顺序是根据用例名称升序进行,而不是用例定义的先后顺序。 在unittest中解决用例执行顺序的问题是使用TestSuite来定义顺序

如何让多个用例共用setup、teardown

unittest的setup、teardown会在每个用例执行前后执行一次,如上面测试用例类中有3个测试用例, 那么每个用例执行前会执行setup,执行后会执行teardown,即setup、teardown总共会调用三次, 但考虑实际自动化测试场景,多个用例只需执行一次setup,全部用例执行完成后,执行一次teardown, 针对该种场景,unittest的处理方法是使用setupclass、teardownclass

如何跳过用例

在自动化测试中,经常会遇到挑选用例的情况,在unittest中的解决方法是使用skip装饰器, 其中skip装饰器主要有3种:unittest.skip(reason)、unittest.skipIf(condition,reason)、 unittest.skipUnless(condition,reason),即在满足condition条件下跳过该用例, reason用于描述跳过的原因

如何生成html格式的测试报告

Unittest中默认生成的报告格式为txt,如果想生成html格式的报告,可以使用HtmlTestRunner模块, 安装后导入该模块,使用HTMLTestRunner代替默认的TextTestRunner()执行测试用例即可。

代码语言:javascript
复制
import unittest
from test_mathfunc import TestMathFunc
from HTMLTestRunner import HTMLTestRunner
 
if __name__ == '__main__':
    suite = unittest.TestSuite()
 
    #使用这种方法可以对测试用例排序
    #tests = [TestMathFunc("test_add"), TestMathFunc("test_minus"), TestMathFunc("test_divide")]
    #suite.addTests(tests)
    
    #使用TestLoader的方法传入TestCase
    suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMathFunc))
 
    #在同目录下生成txt格式的测试报告
    #with open('UnittestTextReport.txt', 'a') as f:
        #runner = unittest.TextTestRunner(stream=f, verbosity=2)
        #runner.run(suite)
 
    with open('HTMLReport.html','w') as f:
        runner = HTMLTestRunner(stream = f,
                                title = u'测试报告',
                                description = u'测试用例的执行情况',
                                verbosity = 2
                                )
        runner.run(suite)

如果我们想执行某个路径下的case:

代码语言:javascript
复制
  for filename in os.listdir(self.cases):
            if filename == "report":
                break
        else:
            os.mkdir(self.cases+'/report')
 
        now = time.strftime("%Y-%m-%d_%H_%M_%S")
        fp = open("./report/"+ now +"result.html", 'wb')
        tests = unittest.defaultTestLoader.discover("./test_case",pattern='*sta.py',top_level_dir=None)
        runner = HTMLTestRunner(stream=fp, title=self.title, description=self.des)
        runner.run(tests)
        fp.close()

队于htmtestrunner这个文件,我们可以去下载:https://www.cnblogs.com/pandaly/p/13212376.html 也可以去https://github.com/huilansame/HTMLTestRunner_PY3

小结:

1、unittest是python自带的单元测试框架,可以用来作为我们自动化测试框架的用例组织执行框架

2、unittest流程:写好TestCase,然后由TestLoader加载TestCase到TestSuite,然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中,我们通过命令行或者unittest.main()执行时,main会调用TextTestRunner中的run来执行,或者我们可以直接通过TextTestRunner来执行用例。

3、一个class继承unittest.TestCase即是一个TestCase,其中以 test 开头的方法在load时被加载为一个真正的TestCase。

4、verbosity参数可以控制执行结果的输出,0 是简单报告、1 是一般报告、2 是详细报告。

5、可以通过addTest和addTests向suite中添加case或suite,可以用TestLoader的loadTestsFrom__()方法。

6、用 setUp()、tearDown()、setUpClass()以及 tearDownClass()可以在用例执行前布置环境,以及在用例执行后清理环境

7、我们可以通过skip,skipIf,skipUnless装饰器跳过某个case,或者用TestCase.skipTest方法。

8、参数中加stream,可以将报告输出到文件:可以用TextTestRunner输出txt报告,以及可以用HTMLTestRunner输出html报告.

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 python粉丝团 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Test Fixture
  • Test Case
  • Test Suite
  • Test Loder
  • Testing Report
  • 如何控制用例执行顺序
  • 如何让多个用例共用setup、teardown
  • 如何跳过用例
  • 如何生成html格式的测试报告
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档