python3学习笔记---测试代码

1、函数测试

Python标准库中的模块unittest提供了代码测试工具。

单元测试用于核实函数的某个方面没有问题;

测试用例是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求。

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

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

name_function.py模块:
def get_formatted_name(first, last):
    """Generate a neatly formatted full name ."""
    full_name = first + " " + last
    return full_name.title()
test_name_function.py 测试函数:

import unittest
from name_functon import get_formatted_name  

class NamesTestCase(unittest.TestCase):  #继承类unittest.TestCase
    """测试name_function.py"""
    def test_first_last_name(self):
        """能够正确处理像JanisJoplin这样的名字吗"""
        formatted_name = get_formatted_name('Janis', 'joplin')
        self.assertEqual(formatted_name, 'Janis Joplin')    #断言方法:用来核实得到的结果是否与期望一致


unittest.main()

>>>

.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

不能通过的测试:

修改get_formatted_name 函数,增加一个中间名,代码如下:

def get_formatted_name(first, middle, last):
    """Generate a neatly formatted full name ."""
    full_name = first + " " + middle + ' ' + last
    return full_name.title()

测试函数不做修改,必然会发生错误,看看测试未通过时,会是什么样子:

E
======================================================================
ERROR: test_first_last_name (__main__.NamesTestCase)
能够正确处理像JanisJoplin这样的名字吗
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:/Users/18969/Desktop/hahh/xx.py", line 8, in test_first_last_name
    formatted_name = get_formatted_name('Janis', 'joplin')
TypeError: get_formatted_name() missing 1 required positional argument: 'last'

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)
测试未通过时怎么办?

如果你检查的条件没错,测试通过了意味着函数的行为是对的,而测试未通过意味着你编写的新代码有错。因此,测试未通过时,不要修改测试,而应修复导致测试不能通过的代码:检查刚对函数所作的修改,找出导致函数行为不符合预期的修改。

修改后的name_function.py 的代码如下:

def get_formatted_name(first, last, middle=""):
    """Generate a neatly formatted full name ."""
    if middle:
        full_name = first + " " + middle + ' ' + last
    else:
        full_name = first + " " + last
    return full_name.title()

测试代码不变,测试结果如下:

.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

添加新测试:

import unittest
from name_functon import get_formatted_name


class NamesTestCase(unittest.TestCase):
    """测试name_function.py"""
    def test_first_last_name(self):
        """能够正确处理像JanisJoplin这样的名字吗"""
        formatted_name = get_formatted_name('Janis', 'joplin')
        self.assertEqual(formatted_name, 'Janis Joplin')

    def test_first_last_middle_name(self):
        """能够正确处理像Wolfgang Amadeus Mozart这样的名字吗?"""
        formatted_name = get_formatted_name('wolfgang', 'mozart', 'amadeus')
        self.assertEqual(formatted_name, 'Wolfgang Amadeus Mozart')


unittest.main()

>>>

..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

2、测试类

断言方法:

Python在unittest.TestCase类中提供了很多断言方法。断言方法检查你认为该满足的条件是否确实满足。如果该条件满足,你对程序的的假设就得到了确认,你就可以确信其中没有错误。如果你认为的应该满足的条件并不满足,Python将引发异常。

unittest Module 中的常用断言方法:

                                 assertEqual(a, b)                  核实 a == b

                                 assertNotEqual(a, b)            核实a != b

                                 assertTure(x)                        核实x为True

                                 assertFalse(x)                       核实x为False

                                 assertIn(item, list)                 核实item在list中

这些断言方法只能在继承unittest.TestCase的类中使用这些方法。

一个要测试的类:

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

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

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

    def store_responses(self, new_response):
        """存储调查问卷"""
        self.responses.append(new_response)

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

此类的使用程序:

from survey import AnonymousSurvey

#定义一个问题, 并创建一个表示调查的Anonymous对象
question = "What language did you 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.store_responses(response)

#显示调查结果
print("\nThank you to everyone who participated in the survey!")
my_survey.show_results()

>>>

What language did you learn to speak?
Enter 'q' at any time to quit.

Language: English
Language: French
Language: Spanish
Language: Chinses
Language: q

Thank you to everyone who participated in the survey!
Survey results: 
- English
- French
- Spanish
- Chinses
测试AnonymousSurvey类:

import unittest
from survey import AnonymousSurvey


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

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

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

    def test_store_three_responses(self):
        """测试三个答案会被妥善地存储"""
        question = "What language did you first learn to speak?"
        my_survey = AnonymousSurvey(question)
        responses = ['English', 'Spanish', 'Mandarin']
        for response in responses:
            my_survey.store_responses(response)

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


unittest.main()

>>>

..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

前述做法很好,但这些测试有些重复的地方,下面使用unittest的另一项功能来提高他们的效率。

方法setUp():

前面的测试中,每个测试方法都创建了一个AnonymousSurvey实例,并在每个方法中都创建了答案。unittest.TestCase类包含方法setup(),让我们只需创建这些对象一次,并在每个测试方法中使用他们。

如果你在TestCase类中包含了方法setUp(), Python将先运行它,再运行各个以test_打头的方法。

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

import unittest
from survey import AnonymousSurvey


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

    def setUp(self):
        """
        创建一个调查对象和一组答案,供使用的测试方法使用
        """
        question = "What language did you first learn to speak?"
        self.my_survey = AnonymousSurvey(question)
        self.responses = ['English', 'Spanish', 'Mandarin']
        
    def test_store_single_response(self):
        """测试单个答案会被妥善保存"""
        self.my_survey.store_responses(self.responses[0])

        self.assertIn(self.responses[0], self.my_survey.responses)

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

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


unittest.main()

>>>

..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

方法setUp()做了两件事情:创建一个调查对象;创建一个答案列表。存储这两样对象的变量名都包含前缀self(即存储在属性中),因此可在这个类的任何地方使用。

测试自己编写的类时,方法setUp()让测试方法编写起来更容易:可在setUp方法中创建一系列实例并设置他们的属性,再在测试方法中直接使用这些实例。

##运行测试用例时,每完成一个单元测试,Python都打印一个字符:测试勇敢时打印一个句点;测试引发错误时打印一个E;测试导致断言失败时打印一个F。这就是你运行测试用例时,在输出的第一行看到的句点和字符数量各不相同的原因。如果测试用例包含很多单元测试,需要运行很长时间,就可通过观察这些结果来获悉有多少个测试通过了。

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值