หนึ่งจะเขียน unittest ที่ล้มเหลวเฉพาะในกรณีที่ฟังก์ชั่นไม่ได้โยนข้อยกเว้นที่คาดไว้?
หนึ่งจะเขียน unittest ที่ล้มเหลวเฉพาะในกรณีที่ฟังก์ชั่นไม่ได้โยนข้อยกเว้นที่คาดไว้?
คำตอบ:
ใช้TestCase.assertRaises
(หรือTestCase.failUnlessRaises
) จากโมดูล unittest ตัวอย่างเช่น:
import mymod
class MyTestCase(unittest.TestCase):
def test1(self):
self.assertRaises(SomeCoolException, mymod.myfunc)
myfunc
คุณต้องเพิ่มเป็นข้อโต้แย้งไปยังการเรียก assertRaises ดูคำตอบของ Daryl Spitzer
self.assertRaises(TypeError, mymod.myfunc)
คำตอบของหม้อข้างต้นตัวอย่างเช่น: คุณสามารถดูรายการข้อยกเว้นในตัวทั้งหมดได้ที่นี่: docs.python.org/3/library/exceptions.html#bltin-exceptions
self.assertRaises(SomeCoolException, Constructor, arg1)
เนื่องจาก Python 2.7 คุณสามารถใช้ตัวจัดการบริบทเพื่อรับ ahold ของวัตถุ Exception ที่เกิดขึ้นจริง:
import unittest
def broken_function():
raise Exception('This is broken')
class MyTestCase(unittest.TestCase):
def test(self):
with self.assertRaises(Exception) as context:
broken_function()
self.assertTrue('This is broken' in context.exception)
if __name__ == '__main__':
unittest.main()
http://docs.python.org/dev/library/unittest.html#unittest.TestCase.assertRaises
ในPython 3.5คุณต้องห่อcontext.exception
ในstr
มิฉะนั้นคุณจะได้รับTypeError
self.assertTrue('This is broken' in str(context.exception))
context.exception
ไม่ให้ข้อความ มันเป็นประเภท
import unittest2
คุณจะต้องใช้คือstr()
self.assertTrue('This is broken' in str(context.exception))
รหัสในคำตอบก่อนหน้าของฉันสามารถทำให้ง่ายขึ้นเพื่อ:
def test_afunction_throws_exception(self):
self.assertRaises(ExpectedException, afunction)
และหากการทะเลาะกันนั้นขัดแย้งกันแค่ส่งพวกเขาไปยัง assertRaises เช่นนี้
def test_afunction_throws_exception(self):
self.assertRaises(ExpectedException, afunction, arg1, arg2)
2.7.15
ฉันใช้ หากafunction
ในself.assertRaises(ExpectedException, afunction, arg1, arg2)
คือการเริ่มต้นเรียนคุณต้องผ่านการself
เป็นเช่นอาร์กิวเมนต์แรก self.assertRaises(ExpectedException, Class, self, arg1, arg2)
คุณจะทดสอบว่าฟังก์ชัน Python ส่งข้อยกเว้นได้อย่างไร
หนึ่งจะเขียนการทดสอบที่ล้มเหลวเฉพาะในกรณีที่ฟังก์ชั่นไม่ได้โยนข้อยกเว้นที่คาดไว้?
ใช้self.assertRaises
วิธีการเป็นผู้จัดการบริบท:
def test_1_cannot_add_int_and_str(self):
with self.assertRaises(TypeError):
1 + '1'
วิธีปฏิบัติที่ดีที่สุดนั้นค่อนข้างง่ายที่จะแสดงใน Python shell
unittest
ห้องสมุด
ใน Python 2.7 หรือ 3:
import unittest
ใน Python 2.6 คุณสามารถติดตั้ง backport ของ 2.7 unittest
ไลบรารีเรียกunittest2และเพียงนามแฝงว่าunittest
:
import unittest2 as unittest
ตอนนี้วางลงใน Python Shell ของคุณเพื่อทดสอบความปลอดภัยของ Python:
class MyTestCase(unittest.TestCase):
def test_1_cannot_add_int_and_str(self):
with self.assertRaises(TypeError):
1 + '1'
def test_2_cannot_add_int_and_str(self):
import operator
self.assertRaises(TypeError, operator.add, 1, '1')
ทดสอบหนึ่งใช้assertRaises
เป็นตัวจัดการบริบทซึ่งทำให้แน่ใจว่าข้อผิดพลาดถูกจับและล้างอย่างถูกต้องขณะบันทึก
เราสามารถเขียนมันโดยไม่ต้องใช้ตัวจัดการบริบทดูทดสอบสอง อาร์กิวเมนต์แรกจะเป็นประเภทข้อผิดพลาดที่คุณคาดว่าจะเพิ่มอาร์กิวเมนต์ที่สองฟังก์ชั่นที่คุณกำลังทดสอบและ args ที่เหลืออยู่และ args คำหลักที่เหลือจะถูกส่งผ่านไปยังฟังก์ชั่นนั้น
ฉันคิดว่ามันง่ายกว่าอ่านและบำรุงรักษาได้มากขึ้นเพื่อใช้ตัวจัดการบริบท
ในการรันการทดสอบ:
unittest.main(exit=False)
ใน Python 2.6 คุณอาจต้องมีสิ่งต่อไปนี้ :
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))
และเทอร์มินัลของคุณควรส่งออกต่อไปนี้:
..
----------------------------------------------------------------------
Ran 2 tests in 0.007s
OK
<unittest2.runner.TextTestResult run=2 errors=0 failures=0>
และเราจะเห็นว่าในขณะที่เราคาดว่าความพยายามที่จะเพิ่ม1
และผลใน'1'
TypeError
สำหรับผลลัพธ์ verbose เพิ่มเติมลองนี้:
unittest.TextTestRunner(verbosity=2).run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))
รหัสของคุณควรเป็นไปตามรูปแบบนี้ (นี่เป็นการทดสอบรูปแบบโมดูลที่ไม่ซับซ้อนที่สุด):
def test_afunction_throws_exception(self):
try:
afunction()
except ExpectedException:
pass
except Exception:
self.fail('unexpected exception raised')
else:
self.fail('ExpectedException not raised')
บน Python <2.7 โครงสร้างนี้มีประโยชน์สำหรับการตรวจสอบค่าเฉพาะในข้อยกเว้นที่คาดไว้ ฟังก์ชั่น unittest assertRaises
จะตรวจสอบว่ามีข้อยกเว้นเกิดขึ้นหรือไม่
assertRaises
คุณจะได้รับข้อผิดพลาดแทน FAIL
จาก: http://www.lengrand.fr/2011/12/pythonunittest-assertraises-raises-error/
ก่อนอื่นนี่คือฟังก์ชั่นที่เกี่ยวข้อง (ยัง dum: p) ในไฟล์ dum_function.py:
def square_value(a):
"""
Returns the square value of a.
"""
try:
out = a*a
except TypeError:
raise TypeError("Input should be a string:")
return out
นี่คือการทดสอบที่จะดำเนินการ (แทรกการทดสอบนี้เท่านั้น):
import dum_function as df # import function module
import unittest
class Test(unittest.TestCase):
"""
The class inherits from unittest
"""
def setUp(self):
"""
This method is called before each test
"""
self.false_int = "A"
def tearDown(self):
"""
This method is called after each test
"""
pass
#---
## TESTS
def test_square_value(self):
# assertRaises(excClass, callableObj) prototype
self.assertRaises(TypeError, df.square_value(self.false_int))
if __name__ == "__main__":
unittest.main()
ตอนนี้เราพร้อมที่จะทดสอบฟังก์ชั่นของเราแล้ว! นี่คือสิ่งที่เกิดขึ้นเมื่อพยายามเรียกใช้การทดสอบ:
======================================================================
ERROR: test_square_value (__main__.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_dum_function.py", line 22, in test_square_value
self.assertRaises(TypeError, df.square_value(self.false_int))
File "/home/jlengrand/Desktop/function.py", line 8, in square_value
raise TypeError("Input should be a string:")
TypeError: Input should be a string:
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (errors=1)
TypeError ถูกยกขึ้นมาใหม่และสร้างความล้มเหลวในการทดสอบ ปัญหาคือว่านี่เป็นพฤติกรรมที่เราต้องการ: s
เพื่อหลีกเลี่ยงข้อผิดพลาดนี้เพียงแค่เรียกใช้ฟังก์ชั่นโดยใช้แลมบ์ดาในการทดสอบการโทร:
self.assertRaises(TypeError, lambda: df.square_value(self.false_int))
ผลลัพธ์สุดท้าย:
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
สมบูรณ์แบบ!
... และสำหรับฉันก็สมบูรณ์แบบเช่นกัน !!
ขอบคุณมากนาย Julien Lengrand-Lambert
ยืนยันการทดสอบนี้จะส่งกลับจริงเท็จบวก ที่เกิดขึ้นเพราะแลมบ์ดาภายใน 'assertRaises' เป็นหน่วยที่ทำให้เกิดข้อผิดพลาดประเภทไม่ใช่ฟังก์ชั่นการทดสอบ
self.assertRaises(TypeError, df.square_value(self.false_int))
เรียกเมธอดและส่งคืนผลลัพธ์ สิ่งที่คุณต้องการคือการผ่านวิธีการและข้อโต้แย้งใด ๆ และปล่อยให้ unittest ที่จะเรียกมันว่า:self.assertRaises(TypeError, df.square_value, self.false_int)
คุณสามารถสร้างของคุณเองcontextmanager
เพื่อตรวจสอบว่ามีการยกข้อยกเว้น
import contextlib
@contextlib.contextmanager
def raises(exception):
try:
yield
except exception as e:
assert True
else:
assert False
จากนั้นคุณสามารถใช้raises
สิ่งนี้:
with raises(Exception):
print "Hola" # Calls assert False
with raises(Exception):
raise Exception # Calls assert True
หากคุณกำลังใช้pytest
สิ่งนี้จะถูกนำไปใช้แล้ว คุณสามารถทำได้pytest.raises(Exception)
:
ตัวอย่าง:
def test_div_zero():
with pytest.raises(ZeroDivisionError):
1/0
และผลลัพธ์:
pigueiras@pigueiras$ py.test
================= test session starts =================
platform linux2 -- Python 2.6.6 -- py-1.4.20 -- pytest-2.5.2 -- /usr/bin/python
collected 1 items
tests/test_div_zero.py:6: test_div_zero PASSED
unittest
โมดูล!
ฉันใช้doctest [1] เกือบทุกที่เพราะฉันชอบความจริงที่ว่าฉันบันทึกและทดสอบฟังก์ชั่นของฉันในเวลาเดียวกัน
ดูรหัสนี้:
def throw_up(something, gowrong=False):
"""
>>> throw_up('Fish n Chips')
Traceback (most recent call last):
...
Exception: Fish n Chips
>>> throw_up('Fish n Chips', gowrong=True)
'I feel fine!'
"""
if gowrong:
return "I feel fine!"
raise Exception(something)
if __name__ == '__main__':
import doctest
doctest.testmod()
หากคุณใส่ตัวอย่างนี้ในโมดูลและเรียกใช้จากบรรทัดคำสั่งทั้งสองกรณีทดสอบจะถูกประเมินและตรวจสอบ
[1] เอกสาร Python: 23.2 doctest - ทดสอบตัวอย่าง Python แบบโต้ตอบ
ฉันเพิ่งค้นพบว่าไลบรารี Mockจัดเตรียมเมธอด assertRaisesWithMessage () (ในคลาสย่อยของ unittest.TestCase) ซึ่งจะตรวจสอบไม่เพียงว่าข้อยกเว้นที่คาดไว้นั้นเพิ่มขึ้น
from testcase import TestCase
import mymod
class MyTestCase(TestCase):
def test1(self):
self.assertRaisesWithMessage(SomeCoolException,
'expected message',
mymod.myfunc)
มีคำตอบมากมายที่นี่ รหัสแสดงวิธีที่เราสามารถสร้างข้อยกเว้นวิธีที่เราสามารถใช้ข้อยกเว้นนั้นในวิธีการของเราและในที่สุดวิธีที่คุณสามารถตรวจสอบในการทดสอบหน่วยข้อยกเว้นที่ถูกต้องถูกยกขึ้น
import unittest
class DeviceException(Exception):
def __init__(self, msg, code):
self.msg = msg
self.code = code
def __str__(self):
return repr("Error {}: {}".format(self.code, self.msg))
class MyDevice(object):
def __init__(self):
self.name = 'DefaultName'
def setParameter(self, param, value):
if isinstance(value, str):
setattr(self, param , value)
else:
raise DeviceException('Incorrect type of argument passed. Name expects a string', 100001)
def getParameter(self, param):
return getattr(self, param)
class TestMyDevice(unittest.TestCase):
def setUp(self):
self.dev1 = MyDevice()
def tearDown(self):
del self.dev1
def test_name(self):
""" Test for valid input for name parameter """
self.dev1.setParameter('name', 'MyDevice')
name = self.dev1.getParameter('name')
self.assertEqual(name, 'MyDevice')
def test_invalid_name(self):
""" Test to check if error is raised if invalid type of input is provided """
self.assertRaises(DeviceException, self.dev1.setParameter, 'name', 1234)
def test_exception_message(self):
""" Test to check if correct exception message and code is raised when incorrect value is passed """
with self.assertRaises(DeviceException) as cm:
self.dev1.setParameter('name', 1234)
self.assertEqual(cm.exception.msg, 'Incorrect type of argument passed. Name expects a string', 'mismatch in expected error message')
self.assertEqual(cm.exception.code, 100001, 'mismatch in expected error code')
if __name__ == '__main__':
unittest.main()
คุณสามารถใช้ assertRaises จากโมดูล unittest
import unittest
class TestClass():
def raises_exception(self):
raise Exception("test")
class MyTestCase(unittest.TestCase):
def test_if_method_raises_correct_exception(self):
test_class = TestClass()
# note that you dont use () when passing the method to assertRaises
self.assertRaises(Exception, test_class.raises_exception)
ในขณะที่คำตอบทั้งหมดนั้นใช้ได้อย่างสมบูรณ์แบบฉันกำลังมองหาวิธีที่จะทดสอบว่าฟังก์ชั่นใดมีข้อยกเว้นโดยไม่ต้องอาศัยกรอบการทดสอบหน่วยและต้องเขียนคลาสทดสอบ
ฉันสิ้นสุดการเขียนต่อไปนี้:
def assert_error(e, x):
try:
e(x)
except:
return
raise AssertionError()
def failing_function(x):
raise ValueError()
def dummy_function(x):
return x
if __name__=="__main__":
assert_error(failing_function, 0)
assert_error(dummy_function, 0)
และมันล้มเหลวในบรรทัดที่ถูกต้อง:
Traceback (most recent call last):
File "assert_error.py", line 16, in <module>
assert_error(dummy_function, 0)
File "assert_error.py", line 6, in assert_error
raise AssertionError()
AssertionError