unittest学习(一)

学习笔记-unittest

笔记目录:笔记本~笔记目录_airtest和selenium那个好用-CSDN博客

昨天下了雨,今天刮了风,明天太阳就出来了

  • 简介
  • 概念
  • 断言
  • 其他相关
  • web自动化小案例

一:简介

单元测试适合白盒或者开发人员做。

单元测试框架可以用来写测试用例,也适合做Web自动化测试、App自动化测试、接口自动化测试等。

Python中有doctest、unittest、pytest、nose等单元测试框架。

(1)什么是单元测试

本质是通过一段代码去验证另一段代码,所以不要单元测试框架也可以写单元测试。

class Calculation:
    """  完成加法计算 """
    def __init__(self, a, b):
        self.a = int(a)
        self.b = int(b)

    # 加法
    def add(self):
        return self.a + self.b
from test.test2 import Calculation


# 测试加法
def test_add():
    c = Calculation(1, 1)
    rs = c.add()
    # 这里我特意断言失败
    assert rs == 3, '加法执行错误'


if __name__ == '__main__':
    test_add()

但这种方法有问题:1是要自己定义失败的提示,2是如果某个测试函数执行失败,后面的测试函数不再执行,3是无法统计结果(编写更多代码可以解决,但偏离测试的初衷)

使用unittest编写测试用例:

import unittest
from test.test2 import Calculation


class TestCalculation(unittest.TestCase):

    def test_add(self):
        c = Calculation(1, 1)
        rs = c.add()
        self.assertEqual(rs, 3)


if __name__ == '__main__':
    unittest.main()

这里有个坑,就是比如我想使用unittest运行单个用例,鼠标在方法名右键执行就行,运行整个的,就在main那里右键执行。(这种方式运行是如python tests那样,因为使用了unittest,默认是使用这种方式运行)

但是这种方式是没有测试报告的,必须这样(如果不知道路径,搞个简单的输出文件复制一下就行)

这样输出就有对应的结果了(也可以吧python tests的删除了,鼠标在main后,就能看到test的run了)

这里结果的含义:

  • .:表示通过
  • E:表示运行错误
  • s:表示运行跳过
  • F:表示运行失败

二:概念

Test Case:最小的测试单元,Unittest提供了TestCase用于创建测试用例

Test Suite:测试套件,用于组装一组要运行的测试,Unittest提供了TestSuite用于创建测试套件

Test Runner:用于协调测试的执行并向用户提供结果,Unittest提供了TextTestRunner用于运行测试用例,提供HTMLTestRunner用于生成HTML测试报告

Test Fixture:代表执行一个或多个测试所需的环境准备,以及关联的清理动作。如setUp、tearDown

import unittest
from test.test2 import Calculation


# 必须继承unittest模块的TestCase类
class TestCalculation(unittest.TestCase):

    # 测试用例前置动作
    def setUp(self):
        print("测试开始")

    # 测试用例后置动作
    def tearDown(self):
        print("测试结束")

    # 测试方法以test开头
    def test_add(self):
        print("第一条测试用例")
        c = Calculation(1, 1)
        rs = c.add()
        # 由于继承了TestCase类,可以通过self直接调用断言方法
        self.assertEqual(rs, 3)

    def test_sub(self):
        print("第二条测试用例")
        c = Calculation(1, 1)
        rs = c.sub()
        # 由于继承了TestCase类,可以通过self直接调用断言方法
        self.assertEqual(rs, 0)


if __name__ == '__main__':
    # 抛弃了这个方法
    # unittest.main()

    # 创建测试套件
    suit = unittest.TestSuite()
    suit.addTest(TestCalculation("test_add"))
    suit.addTest(TestCalculation("test_sub"))

    # 创建测试运行器
    runner = unittest.TextTestRunner()
    runner.run(suit)

好处是可以控制执行顺序,还有需要运行的用例。

三:断言

方法

检查

版本

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

3.1

assertIsNot(a,b)

a is not b

3.1

assertIsNone(x)

x is None

3.1

assertIsNotNone(x)

x is not None

3.1

assertIn(a,b)

a in b

3.1

assertNotIn(a,b)

a not in b

3.1

assertIsInstance(a,b)

Isinstance(a,b)

3.1

assertNotIsInstance(a,b)

Not Isinstance(a,b)

3.1

可以通过这种方式推出断言的使用:

import unittest


class TestAssert(unittest.TestCase):

    def test_equal(self):
        self.assertEqual(1+1, 2)


if __name__ == '__main__':
    unittest.main()

四:其他相关

(1)一个测试类对应一个被测试功能,如加法类,里面有很多方法,如整数相加、小数相加等

格式:

unittest中的TestLoader类提供了discover()方法可以从多个文件中查找测试用例,

不需要创建该类实例,unittest提供了可共享的defaultTestLoader类,可以使用其子类或方法创建实例,再调用discover方法

import unittest

# 测试用例目录
test_dir = './test'
# 测试用例目录、匹配以test开头的多个文件、还有一个参数是top_level_dir=None:测试模块的顶层目录,若没有则默认是None
suits = unittest.defaultTestLoader.discover(test_dir, pattern='test*.py')

if __name__ == '__main__':
    runner = unittest.TextTestRunner()
    runner.run(suits)

(2)测试用例的执行顺序

测试用例的执行顺序涉及多个层级:多个测试目录>多个测试文件>多个测试类>多个测试方法(测试用例)

unittest默认根据ASCII码的顺序加载测试用例(0~9,A~Z,a~z),这是main()方法执行的规律

discover()方法和main()一样,对于测试目录、测试文件同样适用

也可以通过测试套件TestSuite类的addTest()方法按照顺序来加载执行

(3)执行多级目录的测试用例

多个目录,如果discover()方法中的start_dir参数定义为“./test”目录,为了能查到更下层的目录,可以在每个子目录放一个__init__.py文件。作用是将一个目录记为一个标准的python模块。

(4)跳过测试和预期失败

不仅仅可以作用于方法,类也可以,下面是作用于方法

import unittest


class MyTest(unittest.TestCase):

    # 无条件跳过,需要说明跳过测试的原因
    @unittest.skip("直接跳过测试")
    def test_skip(self):
        print("1")

    @unittest.skipIf(2 > 1, "条件为真时跳过测试")
    def test_skip_if(self):
        print("2")

    @unittest.skipUnless(2 > 1, "条件为真时执行")
    def test_skip_unless(self):
        print("3")

    # 不管执行结果是否失败,都将测试标为失败,但不会抛出失败信息(这里我看结果的符号是u)
    @unittest.expectedFailure
    def test_expected_failure(self):
        print("4")


if __name__ == '__main__':
    unittest.main()

(5)Fixture

夹心饼干的饼干,setIp和tearDown,还有更大范围的,如测试类和模块的fIxture

import unittest

# setUpModule和tearDownModule在整个模块的开始与结束执行
def setUpModule():
    print("1")

def tearDownModule():
    print("1-end")

class MyTest(unittest.TestCase):
    # setUpClass和tearDownClass在测试类的开始和结束执行
    # 都是类方法,使用classmethod装饰,cls可以理解为和self一样的表示第一个参数的意思
    @classmethod
    def setUpClass(cls):
        print("2")

    @classmethod
    def tearDownClass(cls):
        print("2-end")

    # setUp和tearDown在测试用例的开始和结束执行,所以先2-测试1-2-end,再2-测试2-2-end
    def setUp(self):
        print("3")

    def tearDown(self):
        print("3-end")

    def test_case1(self):
        print("测试1")

    def test_case2(self):
        print("测试2")


if __name__ == '__main__':
    unittest.main()

五:web自动化小案例

import unittest
from time import sleep

from selenium import webdriver
from selenium.webdriver.common.by import By


class TestBaiDu(unittest.TestCase):

    # 使用这个比setUp好,不用每执行一次用例就重启和关闭一次浏览器,提高效率
    @classmethod
    def setUpClass(cls):
        cls.driver = webdriver.Chrome()
        cls.test_url = "https://www.baidu.com"

    # 封装重复代码(不是test开头,不会当成用例去执行)
    def baidu_search(self, search_key):
        self.driver.get(self.test_url)
        self.driver.find_element(By.ID, "kw").send_keys(search_key)
        self.driver.find_element(By.ID, "su").click()
        sleep(2)

    # 用例1
    def test_search_haha(self):
        search_key = "haha"
        self.baidu_search(search_key)
        title = self.driver.title
        self.assertEqual(title, search_key+"_百度搜索")

    # 用例2
    def test_search_hehe(self):
        search_key = "hehe"
        self.baidu_search(search_key)
        title = self.driver.title
        self.assertEqual(title, search_key+"_百度搜索")

    @classmethod
    def tearDownClass(cls):
        cls.driver.quit()


if __name__ == '__main__':
    unittest.main()

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小chen小陈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值