Python学习日记 Day15测试

今天是2020年2月24日,多云,14~22℃

今天开始上网课了,所幸是自己看视频,可以自由安排时间。不然怕是门门翘课😀

一、测试函数

Python标准库中的 unittest 模块提供了代码测试工具。测试分为1) 单元测试:用于测试函数的某个方面;2) 测试用例:一组单元测试,测试各种情况下的行为;3) 全覆盖式测试:一整套单元测试,涵盖了各种可能的函数使用方式。

1、创建测试

创建测试首先需要导入 unittest 模块,并导入被测试的函数。之后,创建一个继承于 unittest.TestCase 的测试类,并编写测试方法。测试方法应以 test 开头,并大致描述测试的方面。
测试方法中,应调用被测试的函数,然后使用断言方法,比较得到的结果与预期结果是否一致。
例如,对下面一个函数进行测试:

#被测试函数
def get_formatted_time(hour,minute,second):
    '''获取格式化时间'''
    formatted_time = str(hour) + ":" + str(minute) + ":" + str(second)
    return formatted_time

预期该函数应达到返回形如 hh:mm:ss 这一表达时间字符串的效果。
下面创建测试:

import unittest
from mine import get_formatted_time

class TimeTestCase(unittest.TestCase):
    '''测试mine.py'''

    def test_hms_time(self):
        '''能否创建hh:mm:ss形式的字符串?'''
        formatted_time = get_formatted_time(13,52,26)
        self.assertEqual(formatted_time,"13:52:26")

unittest.main()     #运行测试
'''
Output:
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK
'''

分割线上的每一个点表示每一个成功通过测试的函数。在所有测试完成后,将会显示测试所用时间。若测试成功,则会出现OK。

测试类相当于一个测试用例,而类中每一个测试方法相当于一个单元测试。

2、测试失败

上例展示了测试通过时的清醒。下面观察测试失败会发生什么。
首先,将被测试函数加入日期。

def get_formatted_time(year,mouth,day,hour,minute,second):
    '''获取格式化时间'''
    formatted_time = str(year) + '.' + str(mouth) + '.' + str(day)
    formatted_time += ' ' + str(hour) + ':' + str(minute) + ':' + str(second)
    return formatted_time

测试代码不变,再次进行测试。
返回结果如下:

'''
E
======================================================================
ERROR: test_hms_time (__main__.TimeTestCase)
能否创建hh:mm:ss形式的字符串?
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test.py", line 9, in test_hms_time
    formatted_time = get_formatted_time(13,52,26)
TypeError: get_formatted_time() missing 3 required positional arguments: 'hour', 'minute', and 'second'

----------------------------------------------------------------------
Ran 1 test in 0.002s

FAILED (errors=1)
'''

测试未通过时,分割线上方将显示E,表示有一个单元测试未通过。下面的 traceback 说明的错误的位置和类型。最后一行 FAILED 表示整个测试未通过。

3、修改并重新测试

为使函数能满足需求,修改被测试函数:

def get_formatted_time(hour,minute,second,year='',mouth='',day=''):
    '''获取格式化时间'''
    formatted_time = ""
    if year and mouth and day:
        formatted_time = str(year) + '.' + str(mouth) + '.' + str(day) + ' '
    formatted_time += str(hour) + ':' + str(minute) + ':' + str(second)
    return formatted_time

在测试中新增一个测试方法,测试能否得到有年月日的时间。

import unittest
from mine import get_formatted_time

class TimeTestCase(unittest.TestCase):
    '''测试mine.py'''

    def test_hms_time(self):
        '''能否创建hh:mm:ss形式的字符串?'''
        formatted_time = get_formatted_time(13,52,26)
        self.assertEqual(formatted_time,"13:52:26")

    def test_ymdhms_time(self):
        '''能否创建yy.mm.dd hh:mm:ss形式的字符串?'''
        formatted_time = get_formatted_time(14,13,51,year=2020,mouth=2,day=24)
        self.assertEqual(formatted_time,"2020.2.24 14:13:51")


unittest.main()     #运行测试
'''
Output:
..
----------------------------------------------------------------------
Ran 2 tests in 0.002s

OK
'''

由此,我们可以知道现在的函数能完成预期的功能。且当函数修改后,仍能使用这一代码测试函数是否还能完成原功能。

二、测试类

上面学习了针对单个函数的测试。下面将尝试测试整个类。

1、各种断言方法

Python在 unittest 模块中提供了很多断言方法。书上列举的6个常用断言方法如下:

    assertEqual(a,b)        #核实a==b
    assertNotEqual(a,b)     #核实a!=b
    assertTrue(x)           #核实x为True
    assertFalse(x)          #核实x为False
    assertIn(item,list_)     #核实item在list_中
    assertNotIn(item,list_)  #核实item不在list_中
2、创建测试

首先编写一个简单的类。

class School():
    '''保存学校的校内师生名字'''
    
    def __init__(self,school_name):
        '''初始化学校名、学生列表和教师列表'''
        self.school_name = school_name
        self.students = []
        self.teachers = []

    def print_school_name(self):
        '''显示学校名'''
        print(school_name)

    def store_student(self,new_student):
        '''录入新学生名'''
        self.students.append(new_student)

    def store_teacher(self,new_teacher):
        '''录入新教师名'''
        self.teachers.append(new_teacher)

    def print_students(self):
        '''显示学生名单'''
        print("学生名单:\n--------")
        for student in self.students:
            print(student)
        print("--------")

    def print_teachers(self):
        '''显示教师名单'''
        print("教师名单:\n--------")
        for teacher in self.teachers:
            print(teacher)
        print("--------")

    def print_all(self):
        '''显示学校名、学生名单和教师名单'''
        self.print_school_name()
        print("--------")
        self.print_students()
        self.print_teachers()

然后在另一文件中创建测试。

import unittest
from mine import School

class TestSchoolCase(unittest.TestCase):
    '''针对School类测试'''

    def test_store_single_student(self):
        '''测试单个学生名能否储存'''
        school = School("ZSTU")
        school.store_student("Hank")
        self.assertIn("Hank",school.students)

    def test_store_three_teacher(self):
        '''测试三个教师名能否储存'''
        school = School("ZSTU")
        teachers = ["Alex","Blair","Chris"]
        for teacher in teachers:
            school.store_teacher(teacher)
        for teacher in teachers:
            self.assertIn(teacher,school.teachers)


unittest.main()
'''
Output:
..
----------------------------------------------------------------------
Ran 2 tests in 0.002s

OK
'''

测试的过程与函数十分类似。只是在测试方法中需要实例化一个对象,然后做相应测试。

3、setUp方法

在上例的测试中,每个测试方法都单独进行了一次实例化。而 setUp 方法允许我们只需创建一次实例,就可以在所有的测试方法中使用。Python将首先运行 setUp 方法,再运行以 test 开头的方法。

import unittest
from mine import School

class TestSchoolCase(unittest.TestCase):
    '''针对School类测试'''

    def setUp(self):
        '''创建一个实例、一组学生名单和一组教师名单'''
        self.school = School("ZSTU")
        self.students = ["A","B","C"]
        self.teachers = ["1","2","3"]

    def test_store_single_student(self):
        '''测试单个学生名能否储存'''
        self.school.store_student(self.students[0])
        self.assertIn(self.students[0],self.school.students)

    def test_store_three_teacher(self):
        '''测试三个教师名能否储存'''
        for teacher in self.teachers:
            self.school.store_teacher(teacher)
        for teacher in self.teachers:
            self.assertIn(teacher,self.school.teachers)


unittest.main()
'''
Output:
..
----------------------------------------------------------------------
Ran 2 tests in 0.002s

OK
'''

若在每个测试方法中调用 school.print_all 方法,可以发现在上一个单元测试中加入的信息会被清除。
上个测试中加入的学生,在下个测试中不在名单中了。

再查看地址,发现两次测试中实例的地址并不相同。
两次地址不同
由此可以推断,setUp会在每个单元测试前都执行一次,为该单元测试单独创建一个实例,而不是所有的单元测试使用同一个实例。

至此,本人花费了半个月的时间,总算把Python的基本语法和特性了解了一下。虽然学的很浅,也没有做项目,但也算学了点东西,没有完全浪费整个寒假。接下来学校的网课也陆续开始了,重心还是放回课内的学习上。课余时间还会参照书本做一下书上的示例,还有老师安排的项目。困难与经验也尽量隔几天总结一次,发在博客上,不要浪费了半个月每天码字的习惯。希望自己能在下个学期有更多提升,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值