# Python之测试代码 #
由于之前小苏在学习编程语言(C、Java、Python)的很长一段时间里都不知道测试代码的存在,包括当初做仿真比赛的时候只是一味的改变参数,只能从比赛平台上看出细微的差别,现在想起来当初真的是十分的费时费力,后来在王老师的介绍下了解到codewars(一个用于刷题的网站),在这个网站里第一次刷Python的时候对于所给出的题目有许多Tset的代码如下
Test.describe("nb_year")
Test.it("Basic tests")
Test.assert_equals(nb_year(1500, 5, 100, 5000), 15)
Test.assert_equals(nb_year(1500000, 2.5, 10000, 2000000), 10)
Test.assert_equals(nb_year(1500000, 0.25, 1000, 2000000), 94)
当时看到的时候我也是处于很懵的状态,后来知道了测试,了解到在编写函数或者是类的时候,可以为其编写测试。通过测试可以确定自己的代码在面对各种输入时能不能按要求去工作,与此同时,当你在为自己的程序添加上新代码的时候也可以对其进行测试,确认对原有的程序不会造成破坏。
接下来小苏将介绍如何使用Python模块unittest中的工具来测试代码,怎样测试类和函数。
## Python测试函数##
举一个简单的例子,对于一个简单的函数,接受名和姓然后返回一个姓名,代码如下:
### name_test.py ###
def get_formatted_name(first, last):
full_name = first + ' ' + last
return full_name.title()
此程序希望将名和姓合成姓名,之间加一个空格,并将首字母大写再返回结果。接下来写一个函数来检查get\_formatted_name()能否完成期望的工作,代码如下:
### names.py ###
from name_test import get_formatted_name
print("Enter 'q' at anytime to quit.")
while True:
first = input("\nPlease give me a first name:")
if first == 'q':
break
last = input("\nPlease give me a last name:")
if last == 'q':
break
formatted_name = get_formatted_name(first, last)
print("\n Formatted name is " + formatted_name + '.')
此程序从name_test中导入get_formatted_name(),我们输入不含q的名字时即可返回相应的结果如下:
Enter 'q' at anytime to quit.
Please give me a first name:tan
Please give me a last name:susu
Formatted name is Tan Susu.
从结果可以看出,我们的程序最后完成了预期的任务。但是如果想要修改get\_formatted_name()时,我们需要每次都进行测试,运行names.py,在输入像tsn susu这样的名字,就显得很繁琐。所以下面介绍一种自动测试函数输出的高效方式。
### 单元测试&测试用例-unittest模块使用 ###
Python标准库中的模块**unittest**提供了代码测试工具。**单元测试**用于检测函数某个方面没有问题;**测试用例**是一组单元测试,这些单元测试可一起检测函数在不同情形下的行为是否达到预期。通常我们自己写少量代码只用针对代码的某些重要的行为做测试即可,后期开发大型项目时可考虑全覆盖测试。
要为自己的函数添加测试用例,可先导入模块unittest以及测试要用的函数,再创建一个继承unittest.TestCase的类,再编写方法对函数的行为进行测试。
以下是一个只包含一个方法的测试用例,用于检查get\_formatted_name()在给定名和姓时能否达到预期,代码如下:
### test\_name_function.py ###
import unittest
from name_test import get_formatted_name
class NameTestCase(unittest.TestCase):
def test_first_last_name(self):
formatted_name = get_formatted_name('tan' , 'susu')
self.assertEqual(formatted_name,'Tan Susu')
unittest.main()
程序先导入了模块unittest和需要测试的函数get\_formatted\_name(),创建了NameTestCase的类,包含对于get\_formatted_name()的单元测试。类名可以随便取,但是要包含**Test**字样,同时最好看起来与要测试的函数相关,便于自己管理。
NameTestCase只包含一个方法,用于测试get\_formatted\_name()是否能够将输入的名和姓正确的格式化,当运行test\_name\_function.py时test_.py的方法都将自动运行。程序中使用断言的方法,用来最后检测函数返回的结果是否与期望的结果一致。倒数第二行代码self.assertEqual(formatted_name,'Tan Susu')的意思就是将formatted_name的结果与字符串'Tan Susu'进行比较,如果相等就通过,如果不相等就会报错。
## Python测试类 ##
Python中对于类的使用频率也是十分的高,有了对于类的测试,可以更好的检测出自己对于代码的改动有没有对原程序造成破坏。
对于一个要测试的类,代码如下:
### survey.py ###
class AnonymousSurvey():
#收集所有的匿名调查问卷的答案
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_results(self):
#显示所有的答案
print("Survey result:")
for response in self.responses:
print('- ' + response)
为证明AnonymousSurvey类可以达到预期的效果,编写一个使用它的程序,代码如下:
### language_survey.py ###
from survey import AnonymousSurvey
#确定一个问题并创建一个对象
question = "Which is your favorite color ?"
my_survey = AnonymousSurvey(question)
#显示问题并存储答案
my_survey.show_question()
print("Enter 'q' at anytime to quit.\n")
while True:
response = input("color:")
if response == 'q':
break
my_survey.store_response(response)
#显示调查结果
print("\nThanks to everyone who participanted in the survey!")
my_survey.show_results()
最后程序的运行结果如下:
Which is your favorite color ?
Enter 'q' at anytime to quit.
color:blue
color:red
color:yellow
color:q
Thanks to everyone who participanted in the survey!
Survey result:
- blue
- red
- yellow
如果需要对AnonymousSurvey类中的方法进行修改,可能会影响类的当前行为,比如说修改了答案的处理方式,所以最好还是编写针对类的测试,代码如下:
### test_survey.py ###
import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
def test_store_single_response(self):
#保存测试的单个答案
question = "Which is your favorite color ?"
my_survey = AnonymousSurvey(question)
my_survey.store_response('blue')
self.assertIn('blue', my_survey.responses)
unittest.main()
检测过程同上述函数,先导入模块unittest和需要测试的类AnonymousSurvey,测试所用类名为TestAnonymousSurvey继承unittest.TestCase,方法名定为test_store_single_response,这样命名简洁易懂,然后定义问题,创建类的实例my_survey,再将结果存储在my_survey中,最后检查'blue'是否包含在my_survey.responses中,已确定答案被存储。
只是单一的测试一个结果并不能明确得到结果,下面检测提供三个答案时能否很好的被存储,只需要在类里添加一个方法,代码如下:
def test_store_three_responses(self):
# 保存测试的三个答案
question = "Which is your favorite color ?"
my_survey = AnonymousSurvey(question)
responses = ['blue','red','yellow']
for response in responses:
my_survey.store_response(response)
for response in responses:
self.assertIn(response, my_survey.responses)
这样就处理了对于单个和多个答案的不同情况。
## 小结 ##
本期是小苏第一次写文章,主要介绍了Python中的测试代码,主要介绍了怎样使用模块unittest中的工具来为函数和类写测试;怎样编写继承unittest.TestCase的类和编写测试方法的格式;怎样检测输出结果是否与预期相同。测试是很多和我一样的编程小白不怎么熟悉的方面,不是说所有的程序都需要写测试代码,但是如果参与到团队合作的项目之中,最好还是对自己的代码进行单元测试,养成良好的习惯,这样就很容易检查出自己的函数或者是类中的问题,随心所欲地修改代码也不用担心会破坏项目的功能,个人感觉比程序最后出现问题然后debug好很多。
今天的内容就到此为止,感谢大家!
ps
这周并没有想到特别好的topic,但是就想到不论是谁写程序都会出错,所以就决定回来重新学习一下测试,当然也有部分私心,如果单元测试可以用在2d仿真里面,肯定会对项目有很大的推进作用,由于是第一次写推文,可能有许多地方讲的不是很清晰,后面会慢慢改进qwq。(更新时间:不出意外的话应该可以保持一周一推。)
网友评论