python学习笔记(十九)测试类
在上一篇文章中,我们主要了解了针对单个函数的测试,而在这一篇中,我们将要具体学习一下针对类的测试。
1、断言方法
上一篇我曾经提到过断言方法是unittest类最有用的功能之一,主要用来核实得到的结果是否与期望值一致,这里我们来简单看一下几个常用的。
方法 | 用途 |
---|---|
a s s e r t E q u a l ( a , b ) assertEqual(a, b) assertEqual(a,b) | 核实 a = = b a==b a==b |
a s s e r t N o t E q u a l ( a , b ) assertNotEqual(a, b) assertNotEqual(a,b) | 核实 a a a ! = != != b b b |
a s s e r t T r u e ( x ) assertTrue(x) assertTrue(x) | 核实 x x x 为 T r u e True True |
a s s e r t F a l s e ( x ) assertFalse(x) assertFalse(x) | 核实 x x x 为 F a l s e False False |
a s s e r t I n ( i t e m , l i s t ) assertIn(item, list) assertIn(item,list) | 核实 i t e m item item 在 l i s t list list 中 |
a s s e r t N o t I n ( i t e m , l i s t ) assertNotIn(item,list) assertNotIn(item,list) | 核实 i t e m item item 不在 l i s t list list 中 |
注意,我们只能在继承unittest.TestCase的类中使用这些方法。
实际上,类的测试与函数的测试很相似,测试代码的主要功能还是测试类中方法的行为,下面我们主要例子来了解测试类。
2、编写待测试的类
首先,创建一个空文件夹day_19。
在文件 question.py 中编写待测试类 Question(),并将其存放在文件夹day_19中。
class Question():
"""调查问卷"""
def __init__(self, question):
"""初始化问题和答案"""
self.question = question
self.answers = []
def give_question(self):
"""提供问题"""
print(self.question)
def get_answer(self, answer):
"""收集答案"""
self.answers.append(answer)
def show_answer(self):
"""打印收集到的答案"""
print("Results:")
for answer in self.answers:
print("- " + answer)
上述类只是一个空模型,我们可以将其实例化来调查大家最喜欢的编程语言。另创建 favorite_language.py 文件,并保存在 day_19 文件夹中。
from question import Question
question = "Please tell me your favorite programming language?"
answer_got = Question(question)
answer_got.give_question()
print("Please enter 'e' if you want to end.\n")
while True:
response = input("Language: ")
if response == 'e':
break
else:
answer_got.get_answer(response)
answer_got.show_answer()
接下来我们运行一下 favorite_language.py 文件,简单看一下待测试类的基本功能。运行结果为:
Please tell me your favorite programming language?
Please enter 'e' if you want to end.
Language: python
Language: java
Language: ruby
Language: c
Language: e
Results:
- python
- java
- ruby
- c
但是,Question 类是否有什么隐藏问题呢,这时候我们就需要借助测试代码来确定一下。
3、编写测试代码
创建 test_question.py 文件,并存放在 day_19 文件夹中。
import unittest
from question import Question
class TestQuestion(unittest.TestCase):
"""针对Question类的测试代码"""
def test_store_single_answer(self):
"""测试单个答案是否会被存储起来"""
question = "Please tell me your favorite programming language?"
answer_got = Question(question)
answer_got.get_answer('python')
self.assertIn('python', answer_got.answers)
unittest.main()
上述代码只是简单的测试了类存储单个答案的行为,我们来看看测试代码的编写,实际上,与函数的测试代码十分相似:导入 unittest 模块,导入待测类,创建继承TestCase类的测试类,编写以 _test 开头的测试方法,最后一行 unittest.main() 使python自动运行以 _test 开头的方法,稍微有点不同的是我们必须在测试类的方法之前先完成类的实例化。下面我们再来看看运行结果有什么不同:
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
测试通过,一样。接下来我们核实一下用户传入三个答案时,答案能否被正常存储,改写 test_question.py 文件。
import unittest
from question import Question
class TestQuestion(unittest.TestCase):
"""针对Question类的测试代码"""
def test_store_single_answer(self):
"""测试单个答案是否会被存储起来"""
question = "Please tell me your favorite programming language?"
answer_got = Question(question)
answer_got.get_answer('python')
self.assertIn('python', answer_got.answers)
def test_store_three_answers(self):
"""测试三个答案能否被正常存储"""
question = "Please tell me your favorite programming language?"
answer_got = Question(question)
answers = ['python', 'java', 'c']
for answer in answers:
answer_got.get_answer(answer)
for answer in answers:
self.assertIn(answer, answer_got.answers)
unittest.main()
运行结果为:
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
测试通过,但实际上新增的方法与之前的重复性很高,因为他只是设置了列表,再用for循环完成测试,这样代码效率会变低,但是,unittest模块的另一项功能可以帮助我们完美解决这一问题。
4、方法setUp()
在上一篇文章中我曾经提到过,python会自动运行测试类中以 test_ 开头的方法,但是当unittest.TestCase 类中包含 setUp()
方法,python将先运行它,在运行各个以 test_ 开头的方法,我们可以根据这一特性来提高测试类中代码的效率。接下来我们再次改写 test_question.py 文件。
import unittest
from question import Question
class TestQuestion(unittest.TestCase):
"""针对Question类的测试代码"""
def setUp(self):
"""创建一个Question对象和一组答案"""
question = "Please tell me your favorite programming language?"
self.answer_got = Question(question)
self.answers = ['python', 'java', 'c']
def test_store_single_answer(self):
"""测试单个答案是否会被存储起来"""
self.answer_got.get_answer(self.answers[0])
self.assertIn(self.answers[0], self.answer_got.answers)
def test_store_three_answers(self):
"""测试三个答案能否被正常存储"""
for answer in self.answers:
self.answer_got.get_answer(answer)
for answer in self.answers:
self.assertIn(answer, self.answer_got.answers)
unittest.main()
运行结果为:
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
实际上,setUp() 方法就是将其他测试方法中高度重复的部分想办法集中起来,从而提高代码的效率。
5、注意
运行测试用例时,每当完成单元测试,python都打印一个字符:
.
.
. :测试通过
E
E
E :测试引发错误
F
F
F :测试导致断言失败
如果测试用例包含很多单元测试,就需要运行很长时间,我们可以直接根据符号判断测试情况,再结合错误报告被测试的函数或者类。