Unit test定义:
Verifies that one specific aspect of a function’s behavior is correct.
Test case定义:
a collection of unit tests that together prove that a function behaves as it’s supposed to, within the full range of situations you expect it to handle.
一个好的test case至少要包括各类典型的函数输入组合。
测试函数
为函数写test case的步骤:
- import unittest 模块
- 写一个类,继承unittest.TestCase
- 写一系列方法测试函数的各种行为
看一个例子。
首先是待测试的函数:
$ cat name_function.py
def get_formatted_name(first, last, middle=''):
"""Generate a neatly formatted full name."""
if middle:
full_name = f"{first} {middle} {last}"
else:
full_name = f"{first} {last}"
return full_name.title()
然后是测试用例:
$ cat test_name_function.py
import unittest
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase):
"""Tests for 'name_function.py'."""
def test_first_last_name(self):
"""Do names like 'Janis Joplin' work?"""
formatted_name = get_formatted_name('janis', 'joplin')
self.assertEqual(formatted_name, 'Janis Joplin')
def test_first_last_middle_name(self):
"""Do names like 'Wolfgang Amadeus Mozart' work?"""
formatted_name = get_formatted_name(
'wolfgang', 'mozart', 'amadeus')
self.assertEqual(formatted_name, 'Wolfgang Amadeus Mozart')
if __name__ == '__main__':
unittest.main()
这里有些要点:
- 待测试的函数需要有输入和输出
- 测试类NamesTestCase(名字无所谓)继承了unittest.TestCase
- 两个测试用例,方法名都是已
test_
开头,所有以此开头的方法都会自动运行 - assert系列方法会验证输出是否与期望的匹配
if __name__
这句是必要的。当某程序作为主程序运行时,__name__
等于__main__
,当这个文件被import(也就是不是主程序时),__name__
等于文件名(例如name_function.py
就是name_function
)unittest.main()
启动测试
运行测试,2
表示运行了2个测试用例,OK
表示测试成功。两个.
表示两个用例测试均通过,用此可以表示进度,如果不成功,可能是E
或F
:
$ p3 test_name_function.py
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
测试类
unittest.TestCase中包含一系列assert方法:
- assertEqual(a, b)
- assertNotEqual(a, b)
- assertTrue(x),x等于True
- assertFalse(x)
- assertIn(item, list)
- assertNotIn(item, list)
测试类和测试函数并无不同,只不过将调用函数改为实例化类并调用对象的方法。
待测试的类如下:
$ cat survey.py
class AnonymousSurvey:
"""Collect anonymous answers to a survey question."""
def __init__(self, question):
"""Store a question, and prepare to store responses."""
self.question = question
self.responses = []
def show_question(self):
"""Show the survey question."""
print(self.question)
def store_response(self, new_response):
"""Store a single response to the survey."""
self.responses.append(new_response)
def show_results(self):
"""Show all the responses that have been given."""
print("Survey results:")
for response in self.responses:
print(f"- {response}")
测试用例定义如下:
$ cat test_survey.py
import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
"""Tests for the class AnonymousSurvey"""
def setUp(self):
"""
Create a survey and a set of responses for use in all test methods.
"""
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):
"""Test that a single response is stored properly."""
self.my_survey.store_response(self.responses[0])
self.assertIn(self.responses[0], self.my_survey.responses)
def test_store_three_responses(self):
"""Test that three individual responses are stored properly."""
for response in self.responses:
self.my_survey.store_response(response)
for response in self.responses:
self.assertIn(response, self.my_survey.responses)
if __name__ == '__main__':
unittest.main()
要点如下:
setUp
相当于初始化,可以定义在所有测试用例中需要共享的变量。- 需要调用的测试用例名以
test_
开头 - assertIn测试回答是否在列表之中