这篇文章主要介绍了python怎么使用Hypothesis来自动化单元测试,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。
Hypothesis 是一个 Python 库,用于让单元测试编写起来更简单,运行时功能更强大,可以在代码中查找您不会想到的极端情况。它稳定,强大且易于添加到任何现有测试框架中。它的工作原理是让您编写断言每种情况都应该正确的测试,而不仅仅是您偶然想到的那些。
Hypothesis 的基础知识
典型的单元测试需要自己写一些测试用例,然后编写测试函数,通过一段代码运行它,然后根据预期结果检查结果。
Hypothesis 有所不同。它是基于属性进行单元测试。它通过生成与您的规范匹配的任意数据并检查在这种情况下程序是否仍然有效。如果找到了一个失败的用例,它将采用该示例并将其测试用例范围缩减缩减为一定尺寸,然后对其进行简化,直到找到一个仍会导致问题的小得多的示例。然后将其保存,后续单元测试时仍会使用这些用例。
现在就让我们看看怎么用吧。
Hypothesis 快速入门
1、安装
可以通过 pip 安装,也可以通过源代码安装[2],也可以安装一些扩展[3],如下:
pip install hypothesispip install hypothesis[pandas,django]
2、使用
先写一段代码,保存在 mycode.py 中,功能是对字符串进行特定的编码和解码,内容如下:
def encode(input_string): count = 1 prev = "" lst = [] for character in input_string: if character != prev: if prev: entry = (prev, count) lst.append(entry) count = 1 prev = character else: count += 1 entry = (character, count) lst.append(entry) return lstdef decode(lst): q = "" for character, count in lst: q += character * count return q
对这段代码进行单元测试,往往需要写很多测试用例,现在我们使用 hypothesis 来自动为我们测试,编写 test_mycode.py (文件名随意),内容如下:
from hypothesis import givenfrom mycode import decode,encodefrom hypothesis.strategies import textimport unittestclass TestEncoding(unittest.TestCase): @given(text()) def test_decode_inverts_encode(self, s): self.assertEqual(decode(encode(s)), s)if __name__ == "__main__": unittest.main()
可以看出,这里并没有出现具体的测试用例,而是使用来 text 的策略,相当于 hypothesis 自动穷举来可能的情况,也可以看出它很容易可其他测试框架集成,这里是 unittest。现在来运行一下看看效果:
(py38env) ➜ tmp python test_mycode.pyFalsifying example: test_decode_inverts_encode( self=<__main__.TestEncoding testMethod=test_decode_inverts_encode>, s='',)E======================================================================ERROR: test_decode_inverts_encode (__main__.TestEncoding)----------------------------------------------------------------------Traceback (most recent call last): File "test_mycode.py", line 9, in test_decode_inverts_encode def test_decode_inverts_encode(self, s): File "/Users/aaron/py38env/lib/python3.8/site-packages/hypothesis/core.py", line 1162, in wrapped_test raise the_error_hypothesis_found File "test_mycode.py", line 10, in test_decode_inverts_encode self.assertEqual(decode(encode(s)), s) File "/Users/aaron/tmp/mycode.py", line 14, in encode entry = (character, count)UnboundLocalError: local variable 'character' referenced before assignment----------------------------------------------------------------------Ran 1 test in 0.048sFAILED (errors=1)
这里测试出当字符串为 '' 的时候会抛出 UnboundLocalError 的异常。现在我们来修复这个 bug,然后把所有的测试用例 s 给打印出来,看看它用了哪些测试用例。
encode 函数加入以下代码:
if not input_string: return []
test_mycode.py 文件打印出测试用例:
@given(text())def test_decode_inverts_encode(self, s): print(f"{s=}") self.assertEqual(decode(encode(s)), s)
再次执行:
(py38env) ➜ tmp python test_mycode.pys=''s='1's='0's='0's='0's='Ā's='\U000cf5e5's='0's=''s='0's='0's='E's=")dù'\x18\U0003deb3¤jd"s='\U0005bc37\x07\U000537a1ÝÀãiÎ\U000ce9e5\x0b's='\U0005bc37\U0005bc37\U000537a1ÝÀãiÎ\U000ce9e5\x0b's='\U0005bc37\U000537a1\U000537a1ÝÀãiÎ\U000ce9e5\x0b's='À\U000537a1\U000537a1ÝÀãiÎ\U000ce9e5\x0b's='\U000965e1\x12\x85&\U000f500aÄÃc's='\n\U0004466c\x86Î\x07's='Ê\U00063f1e\x01G\x88's='ÚV\n's='VV\n's='\U0008debf湆è's='\U0008debf湆è's='\U0008debf湆's='\U0008debf\U0008debf's='\U0008debf\U0008debfó]½àq\x82#\U00015196\U0001c8beg's='\U0008debfgó]½àq\x82#\U00015196\U0001c8beg's='?'s='Î's='Î\U00085b9e's="Î8'?\U00057c38Ù;\x07\U000a5ea8Ò»=\U00091d5b~8뺈"s='\U000d6497Ý>'s='\U000e0f01's='\U000e0f01Å0y¢KN®'s='\U000e0f01Å0y¢KN®'s='\U00050a06's='Å\U000b98b3か\U000ba80aá`Ã-Êu\x8c\x90³FÔ"'s='\x8e\U0004612a\x83ç's='\x8e's='\x8e\x98\U000fb3e0\U0010d2b3\x10\x82\x94Ð渥's='¥W's='p\U000e5a2aE·`ì's='\U000b80f8\x12\U000c2d54's='.\U000703de's='6\U00010ffa\U000f7994\x8e's='116\U000f7994\x8e's='1?6\U000f7994\x8e's='4?6\U000f7994\x8e's='4\x8e6\U000f7994\x8e's='0's='\U0006a564´Ð\x93ü\x9eb&i\x1cÑ's='\U000ceb6f's='\U000ceb6f\xa0\x08's='\U000ceb6f\xa0\x08's='\U000ceb6fꄃ\x08's='\U000ceb6fꄃ匀\U0007cc15\U000b2aaa×**'s='\U000ceb6fꄃ匀's='匀ꄃ匀's='J\x14?ö's='q)'s='q)'s='q\U00060931's='q6's='\U000e3441's='\U000e3441\U00019958¯'s='\x13's='\U000f34dbk's='Kp&tÛà's='\nö\x93's='\n\n\x93's='\U00019c8dѳ\U00056cbd\U000e3b2f\U00058d302's='\x90=R\x8bß\x03's='\x9a's='\U000147e7's='\U000147e7\x85\U0007a3ef's='\U000147e7\U00050a070Â>'s='\U000a4089\x0eC+RÁ\x02\x97\x9cüÌïSS\U0006cbc5;ÿ~\x16\x019VÇ\U000a32fdQ÷\x15's='ÞÚ¾\x19©Z®'s='ਸ਼æ's='\U000cd45a's='\U000cd45a\U000e15cbÑ\x08J\ueb3eúß\x07I\x91\x9a\x18\x16Ç\x80\x1a's='\x8f}º\x0eq\x0b's='\x0e}º\x0eq\x0b's="\U000e05a3&¶º[fõ\x8bÜR'ͼt\x97íW\x05\U000caea9\U0008fd74\U000e8f1c¹?dfƾ\x13"s='\x10\U000e12e2ù\U0006f96erý\U00014baf\x00\x95\U000dbc92É\U00081613µ\U0003b865Z\U0008cc3c's='ú\U000b561f\x8fÎ's='\tàÖ÷'s='à\x92©Ì\U000618fa\x92's='\U000aaf94\x94\x84\U000cda69\U0005291a\U000a63deþ¿O\x8a>\U000b458bÊ.\U00086f07\x1a's='\U0009754e?U_\xa0\x13PQ\x18º\x07\U0006c9c5.Á's='\U00102456's='³WᵎÕ's='\x14\x1c's='\x14's='\x14\U00105bcd"\x10Ô\x99\U000a5032R\U00056c44V&÷>+\U000aaff2ñ®\U000d7570%ª!\U00032553´8x^«'s='\x00\U000e2ac4¼ÄUrB's='\x00\U000e2ac4¼ÄUrB's='\x00\U000e2ac4¼ÄUrB's='ª\x1aU\x8aÇ\U000b2fb9\U0005a586'.----------------------------------------------------------------------Ran 1 test in 0.180sOK
从执行结果可以看出,'' 首先被测试,其次 hypothesis 使用了大量的极端测试用例,减轻了手写的负担,大大提升了效率。
虽然 hypothesis 具有自动记忆功能,你仍然可以显式的指定某个测试用例一直被测试,而且这是推荐的做法,比如我想在每次的测试中都测试 '',可以这样写:
from hypothesis import given, examplefrom hypothesis.strategies import text@given(text())@example("")def test_decode_inverts_encode(s): assert decode(encode(s)) == s
这一点非常有用,提升了测试代码的可读性,可以用来告诉开发人员或者未来的自己,输入的字符串必须要考虑 '' 的情形。
此外,执行单元测试,不一定要使用 unittest.main(),也可以这样,是不是很方便:
if __name__ == "__main__": test_decode_inverts_encode()
感谢你能够认真阅读完这篇文章,希望小编分享的“python怎么使用Hypothesis来自动化单元测试”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网行业资讯频道,更多相关知识等着你来学习!