我正在编写一些测试实用程序库,可能需要执行以下操作
def assertSomething(test_case, ...):
test_case.assertEqual()
有没有办法跳过传递test_case? e.g。
def assertSomething(...):
get_current_unittest_case().assertEqual()
答案 0 :(得分:0)
AssertionError
如果您只想进行一些检查并使用自定义消息失败,
提出AssertionError
(通过raise
或assert
)即可
走。默认情况下,TestCase.failureException
is AssertionError
,和
fail
(内部由unittest.TestCase
的便利方法使用)
只是加注它。
test_things.py
:
import unittest
def check_is_zero(number):
assert number == 0, "{!r} is not 0".format(number)
def check_is_one(number):
if number != 1:
raise AssertionError("{!r} is not 1".format(number))
class NumbersTest(unittest.TestCase):
def test_one(self):
check_is_one(1)
def test_zero(self):
check_is_zero(0)
TestCase
mixin 添加新断言的简单且相对可读的方法是 制作一个“mixin类”,测试用例将是子类。有时它 很好。
testutils.py
包含mixin:
class ArithmeticsMixin:
def check_is_one(self, number):
self.assertEqual(number, 1)
test_thing.py
,实际测试:
import unittest
import testutils
class NumbersTest(unittest.TestCase, testutils.ArithmeticsMixin):
def test_one(self):
self.check_is_one(1)
如果有很多mixin类,使用base one可能会有所帮助:
import unittest
import testutils
class BaseTestCase(unittest.TestCase, testutils.ArithmeticsMixin):
"""Test case with additional methods for testing arithmetics."""
class NumbersTest(BaseTestCase):
def test_one(self):
self.check_is_one(1)
TestCase
子类可读性较差的是使用特殊基类, thread local (比如全局,但是知道线程)和getter函数。
testutils.py
:
import unittest
import threading
_case_data = threading.local() # thread local
class ImproperlyUsed(Exception):
"""Raised if get_case is called without cooperation of BaseTestCase."""
def get_case(): # getter function
case = getattr(_case_data, "case", None)
if case is None:
raise ImproperlyUsed
return case
class BaseTestCase(unittest.TestCase): # base class
def run(self, *args, **kwargs):
_case_data.case = self
super().run(*args, **kwargs)
_case_data.case = None
def check_is_one(number):
case = get_case()
get_case().assertEqual(number, 1)
当测试用例运行时,self
(测试用例实例)保存为
_case_data.case
,稍后在check_is_one
内(或任何其他功能
从测试方法内部调用并想访问self
)
get_case
将能够引用测试用例实例。注意
运行_case_data.case
后设置为None
,如果
在此之后调用get_case
,ImproperlyUsed
将被提升。
test_thing.py
:
import testutils
def check_is_zero(number): # example of out-of-testutils function
testutils.get_case().assertEqual(number, 0)
class NumbersTest(testutils.BaseTestCase):
def test_one(self):
testutils.check_is_one(1)
def test_zero(self):
check_is_zero(0)
最后,sys._getframe
。
让我们̞̓̐你不需要它,因为它是CPython的一部分,
不是Python。
testutils.py
:
import sys
import unittest
class ImproperlyUsed(Exception):
"""Raised if get_case can't get "self" TestCase instance."""
def get_case():
case = sys._getframe().f_back.f_back.f_locals.get("self")
if not isinstance(case, unittest.TestCase):
raise ImproperlyUsed
return case
def check_is_one(number):
case = get_case()
get_case().assertEqual(number, 1)
sys._getframe
从调用堆栈的顶部返回帧,然后很少
取f_locals
以下的帧,并且self
:实例
unittest.TestCase
。与以前的实现选项一样,有
完整性检查,但这里完成了isinstance
。
test_things.py
:
import unittest
import testutils
def check_is_zero(number): # example of out-of-testutils function
testutils.get_case().assertEqual(number, 0)
class NumbersTest(unittest.TestCase):
def test_one(self):
testutils.check_is_one(1)
def test_zero(self):
check_is_zero(0)
如果您只想为某些新类型提供assertEqual
,
看看addTypeEqualityFunc
。