访问当前的unittest.TestCase实例

时间:2017-07-10 05:13:38

标签: python python-unittest

我正在编写一些测试实用程序库,可能需要执行以下操作

def assertSomething(test_case, ...):
  test_case.assertEqual()

有没有办法跳过传递test_case? e.g。

def assertSomething(...):
  get_current_unittest_case().assertEqual()

1 个答案:

答案 0 :(得分:0)

AssertionError

如果您只想进行一些检查并使用自定义消息失败, 提出AssertionError(通过raiseassert)即可 走。默认情况下,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内(或任何其他功能 从测试方法内部调用并想访问selfget_case将能够引用测试用例实例。注意 运行_case_data.case后设置为None,如果 在此之后调用get_caseImproperlyUsed将被提升。

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)

s̻̙ỵ̞̜͉͎̩s.̠͚̹̦̩͓_̢̬ge̡̯̳̖t̞͚̖̳f̜̪̩̪r̙̖͚̖̼͉̹a͏ṃ̡̹e̞̝̠̙

最后,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