天天看点

快学Python:如何测试函数与类1.测试函数2.测试类

编写代码离不开写测试,只有通过测试才知道代码的逻辑有没有问题,健壮性好不好等,测试让你深信,即便有越来越多的人使用你的程序,它也能一如既往正确地工作。
快学Python:如何测试函数与类1.测试函数2.测试类

1.测试函数

Python标准库中的模块unittest提供了代码测试工具。要进行相关测试,必须要有待测试的函数,创建文件name_function.py,其内容如下:

def get_formatted_name(first,last,middle = ''):
	"""生成整洁的姓名"""
	if middle:
		full_name = f"{first} {middle} {last}"
	else:
		full_name = f"{first} {last}"
	return full_name.title()
           

1.1单元测试和测试用例

1)单元测试

用于核实某个函数的某个方面没有问题。

2)测试用例

是一组单元测试,它们一起核实函数在各种情况下的行为都符合要求。

3)全覆盖测试

测试用例包含一整套单元测试,涵盖了各种可能函数使用的方式。

1.2可通过的测试

import unittest
from name_function import get_formatted_name

class NamesTestCase(unittest.TestCase):
	"""Test the name_function.py"""
	
	def test_first_last_name(self):
		"""能够正确处理姓名吗?"""
		formatted_name = get_formatted_name('sun','wukong')
		self.assertEqual(formatted_name,'Sun Wukong')

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

运行上面测试用例,运行结果:

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

OK
           

1.3未通过的测试

为通过测试很简单,将待测试的函数稍微修改下:

def get_formatted_name(first,last,middle = ''):
	"""生成整洁的姓名"""
	full_name = f"{first} {middle} {last}"
	return full_name.title()
           

运行1.2中的测试用例,则会输出为通过的测试返回。笔者不再尝试。

1.4添加新测试

import unittest
from name_function import get_formatted_name

class NamesTestCase(unittest.TestCase):
	"""Test the name_function.py"""
	
	def test_first_last_name(self):
		"""能够正确处理姓名吗?"""
		formatted_name = get_formatted_name('sun','wukong')
		self.assertEqual(formatted_name,'Sun Wukong')

	def test_first_last_middle_name(self):
		"""测试三个名字"""
		formatted_name = get_formatted_name('sun','wu','kong')
		self.assertEqual(formatted_name,'Sun Kong Wu')

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

运行结果:

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

OK
           

2.测试类

2.1各种断言方法

Python在unittest.TestCase类中提供了很多断言方法。下面列举几个常用的断言方法。

方法 用途
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.2一个要测试的类

类的测试与函数的测试相似,类的测试基本上都是对方法的测试,不过也存在一些不同之处,下面创建一个匿名调查类来进行测试。

class AnonymousServey:
	"""收集匿名调查问卷的答案"""

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


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


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


	def show_result(self):
		"""显示收集到的所有答案"""
		print("Survey results:")
		for response in self.responses:
			print(f"- {response}")
           

下面编写一个测试,对

AnonymousServey

类的行为一个方面进行验证:核实答案列表中是否有指定答案。

import unittest
from survey import AnonymousServey

class TestAnonymousServey(unittest.TestCase):
	"""针对AnonymousServey进行测试"""

	def test_store_single_response(self):
		question = "What language did you first learn to speak?"
		self.my_survey = AnonymousServey(question)
		self.my_survey.store_response('python')
		self.assertIn('python',self.my_survey.responses)

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

上面的测试类先导入

unittest

和要测试的

AnonymousServey

,测试调查问卷的被存储后,测试指定数据是否包含在存储的列表中。我们还可以添加更多维度的测试case,例如测试指定某列表是否包含在存储的列表中。

2.3方法setUp()

如果继续添加测试方法,会有很多重复,如何让公共的变量或者测试数据,在用例执行前就能声明好,而且其他方法都可以公用,如何解决呢?可以使用

setUp()

函数。结合上面的测试用例,看看如何使用

setUp()

函数

import unittest
from survey import AnonymousServey

class TestAnonymousServey(unittest.TestCase):
	"""针对AnonymousServey进行测试"""

	def setUp(self):
		"""创建一个调查对象和一组答案,供测试方法使用"""
		question = "What language did you first learn to speak?"
		self.my_survey = AnonymousServey(question)
		self.tree_responses = ['java','php','python']

	def test_store_single_response(self):
		self.my_survey.store_response(self.tree_responses[0])
		self.assertIn(self.tree_responses[0],self.my_survey.responses)

	def test_store_tree_response(self):
		for response in self.tree_responses:
			self.my_survey.store_response(response)

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

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

方法

setUp()

做了两件事:创建一个调查对象,以及创建一个答案列表。存储这两样东西的变量名包含前缀

self

(即存储在属性中),因此可以类的任何地方进行使用。

注意:单元测试对于一个程序的健壮形特别重要。但是要想要自己的单元测试覆盖自己所写的每个方法,每一行却不是很容易,需要各种条件的设置,对于第三方的调用还可以使用Mock方式进行,此是后话了。