كيف يمكنك اختبار هذا الثعبان وظيفة يلقي استثناء ؟
-
02-07-2019 - |
سؤال
كيف تكتب unittest فشل ذلك إلا إذا كانت الدالة لا رمي المتوقع استثناء ؟
المحلول
استخدام TestCase.assertRaises
(أو TestCase.failUnlessRaises
) من unittest وحدة ، على سبيل المثال:
import mymod
class MyTestCase(unittest.TestCase):
def test1(self):
self.assertRaises(SomeCoolException, mymod.myfunc)
نصائح أخرى
منذ بايثون 2.7 يمكنك استخدام السياق مدير الإتصال الفعلي استثناء كائن طرح:
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
في بيثون 3.5, عليك أن التفاف context.exception
في str
, وإلا سوف تحصل على TypeError
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)
كيف يمكنك اختبار هذا الثعبان وظيفة يلقي استثناء ؟
كيف كتابة اختبار فشل ذلك إلا إذا كانت وظيفة لا يلقي المتوقع استثناء ؟
الجواب القصير:
استخدام self.assertRaises
الطريقة سياق المدير:
def test_1_cannot_add_int_and_str(self):
with self.assertRaises(TypeError):
1 + '1'
مظاهرة
أفضل نهج الممارسة من السهل إلى حد ما تثبت في Python shell.
على unittest
مكتبة
في بايثون 2.7 أو 3:
import unittest
في بيثون 2.6, يمكنك تثبيت backport 2.7 هو unittest
مكتبة تسمى unittest2, و مجرد اسم مستعار كما unittest
:
import unittest2 as unittest
على سبيل المثال الاختبارات
الآن لصق في بيثون قذيفة الاختبار التالي من بيثون نوع الأمان:
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
كما سياق مدير ، مما يضمن أن الخطأ هو صحيح القبض تنظيف, في حين سجلت.
يمكننا أيضا كتابة دون سياق مدير نرى اختبار اثنين.الحجة الأولى أن يكون نوع الخطأ تتوقع زيادة ، والحجة الثانية الدالة أنت اختبار المتبقية وسائط و الكلمة وسائط سيتم تمريرها إلى الدالة.
أعتقد أنه من أكثر بسيطة للقراءة و للصيانة فقط إلى استخدام سياق مدير.
تشغيل الاختبارات
لتشغيل الاختبارات:
unittest.main(exit=False)
في بيثون 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
.
لمزيد من إخراج مطول, جرب هذا:
unittest.TextTestRunner(verbosity=2).run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))
التعليمات البرمجية الخاصة بك ينبغي أن تتبع هذا النمط (هذا هو unittest وحدة أسلوب الاختبار):
def test_afunction_throws_exception(self):
try:
afunction()
except ExpectedException:
pass
except Exception as e:
self.fail('Unexpected exception raised:', e)
else:
self.fail('ExpectedException not raised')
على الثعبان < 2.7 هذا البرنامج مفيد لفحص قيم معينة في من المتوقع أن الاستثناء.على unittest وظيفة assertRaises
يتحقق إلا إذا كان استثناء أثيرت.
من: http://www.lengrand.fr/2011/12/pythonunittest-assertraises-raises-error/
أولا هنا هو الموافق (لا يزال دوم :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 هو actullay المطروحة ، ويولد اختبار الفشل.المشكلة هي أن هذا هو بالضبط السلوك أردنا :ق.
لتجنب هذا الخطأ ببساطة تشغيل وظيفة باستخدام لامدا في اختبار الاتصال :
self.assertRaises(TypeError, lambda: df.square_value(self.false_int))
الناتج النهائي :
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
الكمال !
...و بالنسبة لي هو مثالي جدا!!
Thansk الكثير السيدجوليان Lengrand-لامبرت
يمكنك بناء الخاصة بك 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
يمكنني استخدام 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] بيثون الوثائق:23.2 doctest -- اختبار تفاعلي الثعبان أمثلة
إلقاء نظرة على assertRaises طريقة unittest
وحدة نمطية.
لقد اكتشفت للتو أن وهمية المكتبة يوفر assertRaisesWithMessage (طريقة) (في unittest.TestCase فرعية) ، والتي سوف تحقق ليس فقط أن يتوقع الاستثناء ، ولكن أيضا أن يتم رفعه مع رسالة المتوقع:
from testcase import TestCase
import mymod
class MyTestCase(TestCase):
def test1(self):
self.assertRaisesWithMessage(SomeCoolException,
'expected message',
mymod.myfunc)
يمكنك استخدام 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)
هناك الكثير من الإجابات هنا.رمز يبين كيف يمكننا إنشاء استثناء, كيف يمكننا استخدام هذا الاستثناء في أساليب عملنا ، وأخيرا ، كيف يمكنك التحقق من في unittest الصحيح الاستثناءات التي أثيرت.
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()