Web自动化之Unittest(六)

1 unittest基本概念

unittest是python自带的单元测试框架,有时候又被称为”PyUnit”,是python版本的JUint实现。

在学习使用unittest库之前,我们需要了解一下unittest库的一些重要概念:

test fixture: 代表了用例执行前的准备工作和用例执行之后的清理工作。比如在用例执行前创建临时文件和文件夹,又或者启动1个server进程等;

test case: 测试用例,这个相信大家都不陌生。是测试的最小单位,一般检查一组输入的响应(输出)是否符合预期。unittest模块提供了TestCase类来帮助我们创建测试用例;

test suite: 经常被翻译成”测试套件”,也有人称为”测试套”,是测试用例或测试套件的集合,一般用来把需要一起执行的用例组合到一起;

test runner: 用来执行测试用例并输出测试结果的组件。可以是图形界面或命令行界面;

总之:

test fixture的功能可以理解成是初始化和清理测试数据及环境

test case是测试用例

test suite是用例集合

test runner的作用是运行用例并返回结果

2 unittest基本用法

我们通过最简单的例子来看一下unittest的基本用法

import unittest

class Test(unittest.TestCase):

    def setUp(self):

        print('hello')

    def tearDown(self):

        print('bye')

    def test_001(self):

        print('001')

    def test_002(self):

        print('002')

    def test_003(self):

        print('003')

    def func(self):

        print('func')

if __name__ == '__main__':

unittest.main()

解释一下关键点:

可以通过继承unittest.TestCase类来定义我们自己的测试用例,1个测试用例类下面可以有多个测试方法(test)或者叫做测试点

测试用例中方法名以test开头的方法才是测试方法,比如上面的例子里定义了3个以test开头的方法,分别是test_001,test_002和test_003。非测试方法是不会被test runner执行的

setUp和tearDown这两个方法,这两个方法在测试方法执行前后会被自动调用,主要用作预处理和清理。这两个方法就是我们说的test fixture

通过上面的测试代码我们可以看到,在调用uniitest.main()的时候,框架自动的调用了Test类,因为Test继承自unittest.TesetCase类,所以会被框架识别为测试用例,

最后, unittest.main提供了最简单的运行用例的方式。

当我们从命令行运行上面的代码时,我们可以看到如下的输出

001

002

003

----------------------------------------------------------------------

Ran 3 tests in 0.000s

OK

除了使用unittest.main,还有其他的方式可以运行测试用例,比如把最后2行替换为

# 创建一个测试套件,并向其中加载测试用例

suite = unittest.TestLoader().loadTestsFromTestCase(Test)

# 显式运行测试没并且通过设置verbosity设定对每一个测试方法产生测试结果

unittest.TextTestRunner(verbosity=2).run(suite)

运行用例,结果将会如下所示

001

002

003

test_001 (__main__.Test) ... ok

test_002 (__main__.Test) ... ok

test_003 (__main__.Test) ... ok

----------------------------------------------------------------------

Ran 3 tests in 0.001s

OK

3 各种断言方法

unittest断言

断言是测试用例的核心。我们使用assertEqual()来判断预期结果,用assertTrue()和assertFalse来做是非判断,以及用assertRaises()来判断预期的异常是否有被抛出。这些unittest提供的以assert开头的方法就是断言,一般情况下,每个测试方法里都必须有断言,unittest支持各种断言方法。

import unittest

class Test(unittest.TestCase):

  def setUp(self):

    print('hello')

  def tearDown(self):

    print('bye')

  def test_001(self):

    self.assertEqual('1', '1')

  def test_002(self):

    self.assertEqual('0', '1')

if __name__ == "__main__":

  unittest.main()

断言列表

官方文档

方法 检查点

断言方法

含义

assertEqual(a, b)

a == b

assertNotEqual(a, b)

a != b

assertTrue(x)

bool(x) is True

assertFalse(x)

bool(x) is False

assertIs(a, b)

a is b

assertIsNot(a, b)

a is not b

assertIsNone(x)

x is None

assertIsNotNone(x)

x is not None

assertIn(a, b)

a in b

assertNotIn(a, b)

a not in b

assertIsInstance(a, b)

isinstance(a, b)

assertNotIsInstance(a, b)

not isinstance(a, b)

assertRaises(exc, fun, args, *kwds)

fun(args, *kwds) raises exc

assertRaisesRegexp(exc, r, fun, args, *kwds)

fun(args, *kwds) raises exc and the message matches egex r

assertAlmostEqual(a, b)

round(a-b, 7) == 0

assertNotAlmostEqual(a, b)

round(a-b, 7) != 0

assertGreater(a, b)

a > b 2.7

assertGreaterEqual(a, b)

a >= b

assertLess(a, b)

a < b

assertLessEqual(a, b)

a <= b

assertRegexpMatches(s, r)

r.search(s)

assertNotRegexpMatches(s, r)

not r.search(s)

assertItemsEqual(a, b)

sorted(a) == sorted(b) 也支持unhashable对象

assertDictContainsSubset(a, b)

a里面所有的键值对都在b中存在

4 命令行接口

背景 unittest支持命令行接口,我们可以在命令行里指定运行具体的测试用例。

实例 在test.py中定义了Test1和Test2用例,我们可以从命令行中指定只运行该用例。

import unittest

class Test1(unittest.TestCase):

    def setUp(self):

        print('Test1')

    def tearDown(self):

        print('Test1')

    def test_001(self):

        print('测试Test1 $$$$$$$$$')

class Test2(unittest.TestCase):

    def setUp(self):

        print('Test2')

    def tearDown(self):

        print('Test2')

    def test_001(self):

        print('测试Test2 ########')

if __name__ == '__main__':

unittest.main()

在命令行中执行

python -m unittest test.Tese1

python -m unittest test.Tese2

还可以使用-v参数来获得更详细的输出

$ python -m unittest test.Tese1 -v

5 unittest与selenium

封装待测试功能的操作

1.完成创建Commonlib目录,创建Commonlib.py文件,并将前面封装的selenium拷贝进去

from selenium import webdriver

import time

class Commonshare(object):

    # 初始化方法

    def __init__(self):

        # 创建浏览器对象

        self.driver = webdriver.Firefox()

        # 设置隐式等待

        self.driver.implicitly_wait(5)

        # 设置浏览器的最大化

        self.driver.maximize_window()

    def open_url(self,url):

        # 请求指定站点

        self.driver.get(url)

        time.sleep(3)

    def locateElement(self, locate_type, value):

        # 判断定位方式并调用相关方法

        el = None

        if locate_type == 'id':

            el = self.driver.find_element_by_id(value)

        elif locate_type == 'name':

            el = self.driver.find_element_by_name(value)

        elif locate_type == 'class':

            el = self.driver.find_element_by_class_name(value)

        elif locate_type == 'text':

            el = self.driver.find_element_by_link_text(value)

        elif locate_type == 'xpath':

            el = self.driver.find_element_by_xpath(value)

        elif locate_type == 'css':

            el = self.driver.find_element_by_css_selector(value)

        # 如果el不为None,则返回

        if el is not None:

            return el

    # 指定对某一元素的点击操作

    def click(self, locate_type, value):

        # 调用自己创建的locateElement方法定位元素

        el = self.locateElement(locate_type,value)

        el.click()

        time.sleep(1)

    # 对指定的元素进行数据输入

    def input_data(self,locate_type,value,data):

        # 调用自己创建的locateElement方法定位元素

        el = self.locateElement(locate_type,value)

        el.send_keys(data)

    # 获取指定元素的文本内容

    def get_text(self, locate_type, value):

        # 调用自己创建的locateElement方法定位元素

        el = self.locateElement(locate_type, value)

        return el.text

    # 获取指定元素的属性值

    def get_attr(self, locate_type, value, data):

        # 调用自己创建的locateElement方法定位元素

        el = self.locateElement(locate_type, value)

        return el.get_attribute(data)

    # 收尾清理方法

    def __del__(self):

        time.sleep(3)

        self.driver.quit()

  1. 创建Busniess目录,创建Business.py文件,并编写如下

# 导入已经封装好selenium的CommonShare类

from CommonLib.Commonlib import Commonshare

# 继承CommonShare,继承之后Commonshare中的方法都能使用

class Login(Commonshare):

    def login_yhd(self, user, pwd):

        self.open_url('http://www.yhd.com')

        # 点击登陆

        self.click('class', 'hd_login_link')

        # 输入账号

        self.input_data('id', 'un', user)

        # 输入密码

        self.input_data('id', 'pwd', pwd)

        # 点击登陆

        self.click('id', 'login_button')

if __name__ == '__main__':

    login = Login()

login.login_yhd('xxxxxxx','xxxxxx')

  1. 创建Testcase目录编写测试用例testcase.py文件,如下

import unittest

# 从Business组件中导入我们定义的测试登录的类

from Busniess.Login import Login

class Test(unittest.TestCase):

    def setUp(self):

        print ("开始进行测试")

    def tearDown(self):

        print('测试结束')

    # 正确登录的测试用例

    def test_001(self):

        login = Login()

        login.login_yhd('xxxxx','xxxxx')

        data = login.get_text('class','hd_login_name')

        self.assertEqual('hack_ai_buster',data)

    # 没有输账号密码直接点击登录的测试用例

    def test_002(self):

        login = Login()

        login.login_yhd('','')

        data = login.get_text('id','error_tips')

        self.assertEqual('请输入账号和密码',data)

    # 随意输入账号,不输入密码的测试用例

    def test_003(self):

        login = Login()

        login.login_yhd('hgvjchgc','')

        data = login.get_text('id','error_tips')

        self.assertEqual('请输入密码',data)

    # 用于演示出bug的测试用例

    def test_004(self):

        login = Login()

        login.login_yhd('hgvjchgc','')

        data = login.get_text('id','error_tips')

        # 我们故意写错预期结果,让这个断言抛出

        self.assertEqual('请输入密码itcast',data)

if __name__ == '__main__':

unittest.main()

4.在Testcase目录编写测试用例testcase.py文件,如下

import unittest

from Testcase.testcase import Test

class Suit(unittest.TestCase):

    def test_suit(self):

        # 定义要是用的测试用例列表

        case_list = ['test_002','test_003','test_004']

        # 创建测试套件

        mysuit = unittest.TestSuite()

        # 遍历测试用例列表

        for case in case_list:

            # 将测试用例添加到测试套件中

            mysuit.addTest(Test(case))

        # 运行Runner执行测试,verbosity=2指定为每个测试用例生成报告,run中传入要执行的测试套件

        unittest.TextTestRunner(verbosity=2).run(mysuit)

if __name__ == '__main__':

    unittest.main()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值