是否可以使用 python 装饰器将特定的单元测试指向正在测试的不同实例?

Is it possible to use python decorators to direct specific unit tests toward different instances of what is being tested?

我有一个包含 XML 个字符串的 class。这些是我的模型。

class ContainerForStringXMLs():
    def __init__(self):
        pass

    @staticmethod
    def get_model1(self):
        return """I'm a long string called model1"""

    @staticmethod
    def get_model2(self):
        return """I'm a long string called model2"""

我有一个基础测试 class,它让我可以访问其他测试中的模型(以及其他一些在这里不重要的东西)

class BaseTest(unittest.TestCase):
    def setUp(self, model='model1'):
        self.model=model

        if self.model == 'model1':
            self.test_model = ContainerForStringXMLs.model1()
        elif self.model == 'model2':
            self.test_model = ContainerForStringXMLs.model2()

    def tearDown(self):
        del self.model
        del self.test_model

我的实际测试 class 看起来像这样:

class TestClass(BaseTest):
    def __init__(self):
        pass

    def test_on_model1(self):
        """
        I want to perform this test on model1
        """
        print self.test_model ##would return model 1

    def test_on_model2(self):
        """
        I want to perform this test on model 2 
        """
        print self.testmodel2

我要执行的测试是完全相同的测试,但模型不同,因此我从 xml 中提取的值在每种情况下都会不同。我的问题是:是否有一种很好的 pythonic 方式可以在 TestClass 的模型之间切换?我在想也许是装饰师或某种?

如果我能够使用类似下面的东西来选择我将测试指向哪个模型,那就太好了:

class TestClass(BaseTest):
    def __init__(self):
        pass

    @testmodel1
    def test_on_model1(self):
        """
        I want to perform this test on model1
        """
        print self.test_model ##would return model 1

    @testmodel2    
    def test_on_model2(self):
        """
        I want to perform this test on model 2 
        """
        print self.testmodel2

这种行为可能吗?

“XML 字符串”class 按原样在 models.py 中。 测试助手(基础 class 和装饰器)在 testutils.py:

import unittest
import functools

import models


class BaseTestCase(unittest.TestCase):

    def setUp(self, model='model1'):
        self.model_loader = models.ContainerForStringXMLs
        self.model = model

    @property
    def model_contents(self):
        return getattr(
            self.model_loader, 'get_' + self.model)(self.model_loader)


def use_model(model):
    """Make BaseTestCase-aware test use particular model."""
    def _wrapper(func):
        @functools.wraps(func)
        def _inner(self):
            orig = self.model
            self.model = model
            func(self)
            self.model = orig
        return _inner
    return _wrapper

use_model 是一个采用模型名称 (model) 的装饰器,并且 暂时设置 self.model 为测试方法。 model_contents 是从 ContainerForStringXMLs 获取 XML 字符串的 属性 当前 self.model.

因为 get_model1get_model2 是采用 self 的静态方法 (在你的例子中),在 model_contents 我通过 ContainerForStringXMLs class 为 self(这不是特别好)。如果那不是什么 你想要,将 (self.model_loader) 更改为其他内容(并且, 当然,更改 ContainerForStringXMLs 中的 get_* 方法以匹配 你称呼他们的方式)。鉴于这是一个小问题,我只是假设 只有测试和 BaseTest 可以修改。

test_models.py中有两个测试用例:

from testutils import BaseTestCase, use_model


class TwoModelsWithDefaultModelTest(BaseTestCase):

    def setUp(self):
        BaseTestCase.setUp(self, model='model2')

    @use_model('model1')
    def test_first_model(self):
        self.assertEqual(self.model, 'model1')
        self.assertEqual(
            self.model_contents,
            "I'm a long string called model1")

    def test_second_model(self):
        self.assertEqual(self.model, 'model2')
        self.assertEqual(
            self.model_contents,
            "I'm a long string called model2")

    @use_model('model1')
    def test_first_model_again(self):
        self.assertEqual(self.model, 'model1')
        self.assertEqual(
            self.model_contents,
            "I'm a long string called model1")

    def test_second_model_again(self):
        self.assertEqual(self.model, 'model2')
        self.assertEqual(
            self.model_contents,
            "I'm a long string called model2")


class TwoModelsTestWithoutExplicitSetUp(BaseTestCase):

    @use_model('model1')
    def test_first_model(self):
        self.assertEqual(self.model, 'model1')
        self.assertEqual(
            self.model_contents,
            "I'm a long string called model1")

    @use_model('model2')
    def test_second_model(self):
        self.assertEqual(self.model, 'model2')
        self.assertEqual(
            self.model_contents,
            "I'm a long string called model2")

    def test_first_model_again(self):
        self.assertEqual(self.model, 'model1')
        self.assertEqual(
            self.model_contents,
            "I'm a long string called model1")

    @use_model('model2')
    def test_second_model_again(self):
        self.assertEqual(self.model, 'model2')
        self.assertEqual(
            self.model_contents,
            "I'm a long string called model2")

TwoModelsWithDefaultModelTest 调用 BaseTestCase.setUpself.model 设置为 'model2' 用于不使用的测试 use_model 装饰器。 TwoModelsTestWithoutExplicitSetUp 使用 BaseTestCase.setUp 的默认实现没有改变 model 参数默认,所以默认 self.model'model1'.


根据 print 语句判断,您使用 Python 2. 您 should 制作 ContainerForStringXMLs 继承自 object.