Python标准库中的模块unittest测试用例



1. unittest.TestCase类中的常用的断言方法

方法用途
assertEqual(a, b)核实 a == b
assertNotEqual(a, b)核实 a != b
assertTrue(x)核实 x 为True
assertFalse(x)核实 x 为False
assertIn(itemlist)核实itemlist
assertNotIn(itemlist)核实item不在list

断言方法是用来检查你认为该满足的条件是否满足。如果该条件确实满足,你对程序行为的假设就得到了确认,你就可以确信其中没有错误。如果你认为应该满足的条件实际上并不满足,Python将引发异常。

2. 编写函数

编写一个函数,它接受两个形参:一个城市名和一个国家名。这个函数返回一个格式为City, Country的字符串,如 Beijing,China。

# 这是city_functions.py文件
def city(city, country):
    """一个城市及其国家"""
    repo_city = city + ', ' + country
    return repo_city.title()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

编写另一个程序,导入city_functions.py文件的city()函数。

# 这是city.py文件
from city_functions import city
print('可以在任何时候输入 q 退出程序:')
while True:
    city_name = input("\n输入城市名 -> ")
    if city_name == 'q':
        break
    country_name = input("输入国家名 -> ")
    if country_name == 'q':
        break

    city_country = city(city_name, country_name)
    print('\t这个城市和国家是 ' + city_country)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

3. 写测试用例

3.1 先来了解下Python标准库中的模块unittest提供的代码测试工具:
  • 单元测试
  • 测试用例
  • 全覆盖式测试用例

1.单元测试 用于核实函数的某个方面没有问题的。 
2.测试用例 是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求。良好的测试用例考虑到了函数可能收到的各种输入,包含针对所有这些情形的测试。 
3.全覆盖式测试用例 那就是测试用例的终极版本了。它包含一整套单元测试,涵盖了各种可能的函数使用方式。对大型项目而言,要实现全覆盖式测试用例是有一定难度的。(我也不了解)

3.2 开始写测试了
# 这是test_city_function.py文件
from city_functions import city
import unittest
class TestCity(unittest.TestCase):
    """测试city_functions.py"""

    def test_city_country_by_chinese(self):
        """测试'深圳, 中国'能否通过"""
        city_country = city('深圳', '中国')
        self.assertEqual(city_country, '深圳, 中国')

unittest.main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  1. 首先,在这里要导入模块unittest和要进行测试的函数 city()

  2. 接着,创建一个名为TestCity的类,类名可以随便起,但当这测试的函数过多时,为了能方便快速知道这是测试哪个函数的,起类名时尽量取个与要测试的函数的相关的类名,同时包含Test字样。这个类必须继承unittest.TestCase类,这样Python才知道如何运行你编写的测试。

  3. 在类中,编写一个名为test_city_country_by_chinese的方法,用来测试在输入中文的城市和国家名这个方面,即是一个单元测试。在这个方法中,用 test_开头命名这个方法,是因为当执行 test_city_function.py时,所以以test_开头的方法会自动执行。方法名也应该与要测试的某个方面相关。当然也也不是强迫性的,但这样命名是个良好的编码习惯。

  4. 在这个方法中,我们要调用要测试的函数city(),并给这个函数两个实参‘深圳’和‘中国’。并存储了要测试的函数的返回值给变量city_country

  5. 接下来,使用了unittest最经常使用到的功能:断言方法。用来核实得到的结果是否与期待的结果相一致。如果一致,万事大吉,如果不一致,就会引发异常。

  6. unittest.main()让Python运行这个文件中的测试。

现在来执行下这个测试文件test_city_function.py。看看结果:

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

OK
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

上面有个第一行有个点.表明有一个测试通过了,最后的OK表明该测试用例中所有的单元测试都通过了。

这个输出表明,给定城市名和国家名,函数city()总是能正确地处理。

现在让我们来看看输入英文情况下函数city()能否正确处理即格式。因为在函数city中有个功能是将城市名和国家名的首字母大写返回,而中文的无法这样处理的。

在这个类TestCity中编写另个一个单元测试:

# 这是test_city_function.py文件
def test_city_country_by_english(self):
    """测试‘Shenzhen, China’能否正确显示其格式"""
    city_country = city('shenzhen', 'china')
    self.assertEqual(city_country, 'Shenzhen, China')
unittest.main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

其结果:

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

OK
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

ok表明英文输入情况下函数city()是可以正确处理其格式的。

3.3 不能通过的测试

现在这两个都能正常通过测试,但实际上的代码很有可能存在错误。现在我们假设在程序中还有一个条件是可以加入人口数的。而我们知道现在的程序没有这个功能。我们来写个测试当加入人口数的时候错误是如何提示。

# 这是test_city_function.py文件
def test_city_country_population(self):
    """测试‘Shenzhen, China - population 20000000’能否通过"""
    city_country = city('Shenzhen', 'China', 20000000)
    self.assertEqual(city_country, 'Shenzhen, China - population 20000000')
unittest.main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

执行测试文件应可以看到这样的错误:

..E
======================================================================
ERROR: test_city_country_population (__main__.TestCity)
测试‘Shenzhen, China, 20000000’能否通过
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_city_function.py", line 21, in test_city_country_population
    city_country = city('Shenzhen', 'China', 20000000)
TypeError: city() takes 2 positional arguments but 3 were given

----------------------------------------------------------------------
Ran 3 tests in 0.001s

FAILED (errors=1)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在第一行中,可以看到..E中有两个点和一个字符E,表名前两个单元测试通过了,第三个没有通过。接下来我们看看错误的信息提示:可以知道是在方法test_city_country_population()中出了问题。从TypeError中提示:city() takes 2 positional arguments but 3 were given,知道city()只有两个形参,但我们提供了三个实参。

看到这里,如果不是测试代码本身有问题,一旦测试未通过,不要修改测试,而应该去修改导致测试不能通过的代码。所以我们要去修改city_function.py文件的代码。

但,我们知道了错误的原因,是因为缺少一个参数,但是我们添加参数的时候不能导致前面的两个测试不能通过,所以第三个参数的解决方法是让这个个参数是可选的。

 NOTE:实际我在运行中,可以通过,原因待查。


下面修改代码:

def city(city, country, population=''):
    """一个城市及其国家"""
    if population:
        repo_population = ' - population ' + population
        repo_city = city + ', ' + country
        return repo_city.title() + repo_population
    else:
        repo_city = city + ', ' + country
        return repo_city.title()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

运行测试文件:

...
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

从结果中,我们修改的代码既不影响两个参数输入的测试,又满足添加人口数的测试。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值