python入门_day11_Chap11_测试函数和测试类

11.1 测试函数

首先编写待会儿进行测试的代码。
下面是一个简单的函数,它接受名和姓并返回整洁的姓名:
name_function.py

def get_formatted_name(first,last):
    full_name=first+' '+last
    return full_name.title()

names.py

#从name_function.py中导入get_formatted_name() 
from name_function import get_formatted_name

print("Enter 'q' at anny time to quit.")
while True:
    first=input("\nPlease enter your fisrt name:")
    if first=='q':
        break
    last=input("\nPlease enter your last name: ")
    if last=='q':
        break

    formatted_name=get_formatted_name(first,last)
    print("\tNeatly formatted name: "+formatted_name+'.')

运行结果:
在这里插入图片描述

1.单元测试和测试用例

单元测试 用于核实函数的某个方面没有问题;
测试用例 是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求。
全覆盖式测试 用例包含一整套单元测试,涵盖了各种可能的函数使用方 式。

通常,最初只要针对代码的重要行为编写测试即可,等项目被广泛使用时再考虑全覆盖。

2.可通过的测试

要为函数编写测试用例,可先导入模块unittest 以及要测试的函 数,再创建一个继承unittest.TestCase 的类,并编写一系列方法对函数行为的不同方面进行测试。

下面是一个只包含一个方法的测试用例,它检查函数get_formatted_name() 在给定名和姓时能否正确地工作:

test_name_function.py

import unittest
from name_function import get_formatted_name

#创建一个名为NamesTestCase的类,用于包含一系列针对get_formatted_name() 的单元测试
#这个类必须继承 unittest.TestCase 类
class NamesTestCase(unittest.TestCase):
    """测试name_function.py"""

    def test_first_last_name(self):
        formatted_name=get_formatted_name('janis','joplin')
        self.assertEqual(formatted_name,'Janis Joplin')

unittest.main()

我们运行testname_function.py 时 , 所 有 以 test 打头的方法都将自动运行。在这个方法中,我们调用了要测试的函数,并存储了要测试的返回值。

unittest 类最有用的功能之一:一个断言方法,用于核实得到的值是否和期望值相同。

我们知道get_formatted_name() 应 返回这样的姓名,即名和姓的首字母为大写,且它们之间有一个空格,因此我们期望formatted_name 的值为Janis Joplin 。

为检查是否确实如此,我们调用unittest 的方法assertEqual() ,并向它传递formatted_name 和’Janis Joplin’ 。

代码行self.assertEqual(formatted_name, ‘Janis Joplin’) 的意思是 说:“formatted_name 的值同字符串’Janis Joplin’ 进行比较,如果它们相等,就ok,如果它们不相等,会反馈。”

代码行unittest.main() 让Python运行这个文件中的测试。
运行结果:
在这里插入图片描述

3.不能通过的测试

修改name_function.py

def get_formatted_name(first,middle,last):
    full_name=first+' '+middle+' '+last
    return full_name.title()

再次运行test_name_function运行结果
在这里插入图片描述

4.测试未通过时怎么办

下面来修改get_formatted_name() ,将中间名设置为可选的,然后再次运行这个测试用例。如果通过了,我们接着确认这个函数能够妥善地 处理中间名。

要将中间名设置为可选的,可在函数定义中将形参middle 移到形参列表末尾,并将其默认值指定为一个空字符串。我们还要添加一个if 测试,以便根据是否提供了中间名相应 地创建姓名:

def get_formatted_name(first,last,middle=''):
    if middle:
        full_name=first+' '+midlle+' '+last
    else:
        full_name=first+' '+last
    return full_name.title()

运行结果:
在这里插入图片描述

5.添加新测试

确定get_formatted_name() 又能正确地处理简单的姓名后,我们再编写一个测试,用于测试包含中间名的姓名。
为此,我们在NamesTestCase 类中再添加一个方法:

import unittest
from name_function import get_formatted_name

class NamesTestCase(unittest.TestCase):
    """测试name_function.py"""

    def test_first_last_name(self):
        formatted_name=get_formatted_name('janis','joplin')
        self.assertEqual(formatted_name,'Janis Joplin')

    def test_first_last_middle_name(self):
        formatted_name=get_formatted_name('robert','downey','john')
        self.assertEqual(formatted_name,'Robert John Downey')

unittest.main()

运行结果:
在这里插入图片描述

练习
1 . 城市和国家 :编写一个函数,它接受两个形参:一个城市名和一个国家名。这个函数返回一个格式为City, Country 的字符串,如Santiago, Chile 。将 这个函数存储在一个名为city_functions.py的模块中。
创建一个名为test_cities.py的程序,对刚编写的函数进行测试(别忘了,你需要导入模块unittest 以及要测试的函数)。编写一个名为test_city_country() 的 方法,核实使用类似于’santiago’ 和’chile’ 这样的值来调用前述函数时,得到的字符串是正确的。运行test_cities.py ,确认测 试test_city_country() 通过了。

city_functions.py

def get_city_country(city,country):
    msg=city+','+country
    return msg.title()

test_cities.py

import unittest
from city_function import get_city_country

class CityCountryTest(unittest.TestCase):

    def test_city_country(self):
        city_country_msg=get_city_country('beijing','china')
        self.assertEqual(city_country_msg,'Beijing,China')
    
unittest.main()

运行结果:
在这里插入图片描述
2.人口数量 :修改前面的函数,使其包含第三个必不可少的形参population ,并返回一个格式为City, Country - population xxx 的字符串, 如Santiago, Chile - population 5000000 。运行test_cities.py,确认测试test_city_country() 未通过。

def get_city_country(city,country,popluation):
    msg=city+','+country+'-'+population
    return msg.title()

运行结果:
在这里插入图片描述
修改上述函数,将形参population 设置为可选的。再次运行test_cities.py,确认测试test_city_country() 又通过了。

city_function.py

def get_city_country(city,country,popluation=''):
    if popluation:
        msg=city+','+country+'-'+population
    else:
        msg=city+','+country
    return msg.title()

再次运行test_cities.py:
在这里插入图片描述
再编写一个名为test_city_country_population() 的测试,核实可以使用类似于’santiago’ 、‘chile’ 和’population=5000000’ 这样的值来调用 这个函数。再次运行test_cities.py,确认测试test_city_country_population() 通过了。

 import unittest
from city_function import get_city_country

class CityCountryTest(unittest.TestCase):

    def test_city_country(self):
        city_country_msg=get_city_country('beijing','china')
        self.assertEqual(city_country_msg,'Beijing,China')

    def test_city_country_population(self):
        city_country_msg=get_city_country('wuhan','china','80000')
        self.assertEqual(city_country_msg,'Wuhan,China-80000')
    
unittest.main()

运行结果:
在这里插入图片描述

11.2测试类
1.各种断言方法

Python在unittest.TestCase 类中提供了很多断言方法。

方法用途
assertEqual(a,b)核实a==b
assertNotEqual(a,b)核实a!=b
assertTrue(x)核实x为True
assertIn(item,list)核实item在list中
assertNotIn(item,list)核实item不在list中
2.一个要测试的类

类的测试与函数的测试相似——你所做的大部分工作都是测试类中方法的行为,但存在一些不同之处,下面来编写一个类进行测试。

来看一个帮助管理匿名调查的类:

class AnonymousSurvey():
    """收集匿名调查问卷的答案"""


    def __init__(self,question):
        """ 存储一个问题,并为存储答案做准备"""
        self.question=question
        self.responses=[]


    def show_question(self):
        """ 显示调查问卷"""
        print(self.question)


    def stored_response(self,new_response):
        """存储单份调查答案"""
        self.responses.append(new_response)


    def show_results(self):
        """显示收集到的所有答卷 """
        print("Survey results:")
        for response in self.responses:
            print("-"+response)

language_survey.py

from survey import AnonymousSurvey

#定义一个问题,并创建一个表示调查的AnoymouSurvey对象
question="What language did you first learn to speak?"
my_survey=AnonymousSurvey(question)


#显示问题并存储答案
my_survey.show_question()
print("Enter 'q' at any time to quit.\n")
while True:
    response=input("Language: ")
    if response=='q':
        break
    my_survey.stored_response(response)


#显示调查结果
print("\n Thank u for participating in the survey!")
my_survey.show_results()

运行结果:
在这里插入图片描述

3.测试AnonymousSurvey类

下面来编写一个测试,对AnonymousSurvey 类的行为的一个方面进行验证:
如果用户面对调查问题时只提供了一个答案,这个答案也能被妥善地存储。为此,我们将在这个答 案被存储后,使用方法assertIn() 来核实它包含在答案列表中:

import unittest
from survey import AnonymousSurvey

class TestAnonymousSurvey(unittest.TestCase):
    """ 针对AnonyousSurvey类的测试"""

    def test_stored_single_response(self):
        """ 测试单个单元会被妥善的存储"""
        question="What language did you first learn to speak?"
        my_survey=AnonymousSurvey(question)
        my_survey.stored_response('English')

        self.assertIn('English',my_survey.responses)


unittest.main()

运行结果:
在这里插入图片描述

下面来核实用户提供三个答案时,它们也将被妥善地存储。
为此,我们在TestAnonymousSurvey 中再添加一个方法:

import unittest
from survey import AnonymousSurvey

class TestAnonymousSurvey(unittest.TestCase):
    """ 针对AnonyousSurvey类的测试"""

    def test_stored_single_response(self):
        """ 测试单个答案会被妥善的存储"""
        question="What language did you first learn to speak?"
        my_survey=AnonymousSurvey(question)
        my_survey.stored_response('English')

        self.assertIn('English',my_survey.responses)


    def test_stored_three_responses(self):
        """测试三个答案会被妥善的存储"""
        question="What language did you first learn to speak?"
        my_survey=AnonymousSurvey(question)
        responses=['chinese','english','french']
        for response in responses:
            my_survey.stored_response(response)

        for response in responses:
            self.assertIn(response,my_survey.responses)
        
        

unittest.main()

我们定义了一个包含三个不同答案的列表responses,再对其中每个答案都调用store_response() 。存储这些答案后,我们使用一个循环来确认每个答案都包含在my_survey.responses 中。

运行结果是两个测试都通过了:
在这里插入图片描述

4.方法setUp()

在前面的test_survey.py中,我们在每个测试方法中都创建了一个AnonymousSurvey 实例,并在每个方法中都创建了答案。

unittest.TestCase 类包含方法setUp() ,让我 们只需创建这些对象一次,并在每个测试方法中使用它们。如果你在TestCase 类中包含了方法setUp() ,Python将先运行它,再运行各个以test_打头的方法。这样,在你编写 的每个测试方法中都可使用在方法setUp() 中创建的对象了。

下面使用setUp() 来创建一个调查对象和一组答案,供方法test_store_single_response() 和test_store_three_responses() 使用: import unittest 。

import unittest
from survey import AnonymousSurvey

class TestAnonymousSurvey(unittest.TestCase):
    """ 针对AnonyousSurvey类的测试"""

    def setUp(self):
        question="What language did you first learn to speak?"
        self.my_survey=AnonymousSurvey(question)
        self.responses=['chinese','english','french']


    def test_stored_single_response(self):
        """ 测试单个答案会被妥善的存储"""
        self.my_survey.stored_response(self.responses[0])
        self.assertIn(self.responses[0],self.my_survey.responses)


    def test_stored_three_responses(self):
        """测试三个答案会被妥善的存储"""
        for response in self.responses:
            self.my_survey.stored_response(response)

        for response in self.responses:
            self.assertIn(response,self.my_survey.responses)
        
        

unittest.main()

练习
1.雇员:编写一个名为Employee 的类,其方法__init__() 接受名、姓和年薪,并将它们都存储在属性中。

class Employee:

    
    def __init__(self,first,last,salary):
        self.first=first
        self.last=last
        self.salary=salary


    def give_raise(self,increment=5000):
        self.salary+=increment

    def show_employee(self):
        print(self.first+' '+self.last+"'s salary:"+str(self.salary))

编写一个名为give_raise() 的方法,它默认将 年薪增加5000美元,但也能够接受其他的年薪增加量。 为Employee 编写一个测试用例,其中包含两个测试方法:test_give_default_raise() 和test_give_custom_raise() 。

import unittest
from employee import Employee

class TestEmployee(unittest.TestCase):


    def test_give_default_raise(self):
        my_employee=Employee('ming','jing',180000)
        my_employee.give_raise()
        my_employee.show_employee()
        self.assertEqual(185000,my_employee.salary)


    def test_give_custom_raise(self):
        my_employee=Employee('ming','jing',180000)
        my_employee.give_raise(8000)
        my_employee.show_employee()
        self.assertEqual(188000,my_employee.salary)
        
    

unittest.main()

运行结果:
在这里插入图片描述

使用方法setUp() ,以免在 每个测试方法中都创建新的雇员实例。运行这个测试用例,确认两个测试都通过了。

import unittest
from employee import Employee

class TestEmployee(unittest.TestCase):


    def setUp(self):
        self.my_employee=Employee('ming','jing',180000)
        self.my_employee.show_employee()
        

    def test_give_default_raise(self):
        self.my_employee.give_raise()
        self.my_employee.show_employee()
        self.assertEqual(185000,self.my_employee.salary)


    def test_give_custom_raise(self):
        self.my_employee.give_raise(8000)
        self.my_employee.show_employee()
        self.assertEqual(188000,self.my_employee.salary)
        
    
unittest.main()

运行结果:
加上了shoe_employee打印雇员信息的方法,更加清晰的看到方法调用的顺序。
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值