如何对这个python类进行单元测试?

时间:2017-10-18 21:28:36

标签: python unit-testing serialization package factory-pattern

我的代码可测试性存在问题。这与我的类布局和我的python包布局有关。

我希望这个问题有下列结果之一:

  1. 有关更改课程布局的建议,或
  2. 建议更改包装布局,或
  3. 提示如何在没有布局更改的情况下测试这些内容
  4. 类层次结构

    基类是^。这两个类AuthenticationTokenHardwareToken继承自它。

    Keyfile可以序列化为字符串,反之亦然。这就是我实现反序列化的方法:

    AuthenticationToken

    python包布局

    每个类我有一个文件并将它们放入包目录

    class AuthenticationToken(object):
    
        @classmethod
        def try_deserialize(cls, spec: str):
            for subclass in cls.__subclasses__():
                token = subclass.try_deserialize(spec)
                if token:
                    return token
            return None
    

    现在我更喜欢引用类似package +-- __init__.py +-- authentication_token.py +-- hardware_token.py +-- keyfile.py 而不是package.Keyfile的类。在使用package.keyfile.Keyfile方法之前,python还可以看到Authentication标记的所有子类定义。这就是我在try_derialize中导入所有类的原因:

    __init__.py

    可测试性问题

    现在我想在不引用其子类的情况下对from .authentication_token import AuthenticationToken from .hardware_token import HardwareToken from .keyfile import Keyfile 类进行单元测试。我们的想法是编写一个AuthenticationToken类,并在测试期间将其用作单个子类:

    TestAutheticationToken

    此测试失败,因为import unittest from package import AuthenticationToken class TestSubclass(AuthenticationToken): pass class TestAuthenticationToken(unittest.TestCase): # This test fails def test_bad_case(self): should_be_none = AuthenticationToken.try_deserialize("Keyfile") self.assertIsNone(should_be_none) if __name__ == '__main__': unittest.main() 创建了try_deserialize类型的对象。这是因为评估了Keyfile。如果我直接从模块导入__init__.py,情况也是如此:

    AuthenticationToken

    问题

    所以问题是:如何在测试from package.authentication_token import AuthenticationToken 时阻止导入类KeyfileHardwareToken

    或者我如何更改类和/或包布局,以便我可以相互独立地导入所有类,同时仍保留上述优点?

1 个答案:

答案 0 :(得分:0)

代码很难测试,因为令牌提供程序列表是隐式。这取决于已加载的模块。我建议你至少给出明确的令牌提供者列表的选项。要么在启动时注册令牌提供程序,要么为令牌提供程序列表提供可选参数。

这是我能想到的最简单的改变:

class AuthenticationToken(object):

    @classmethod
    def try_deserialize(cls, spec: str, token_providers=None):
        if token_providers is None:
            token_providers = cls.__subclasses__()
        for subclass in token_providers:
            token = subclass.try_deserialize(spec)
            if token:
                return token
        return None

现在你的常规代码没有变化,你的测试看起来像这样:

    def test_bad_case(self):
        should_be_none = AuthenticationToken.try_deserialize(
            "Keyfile",
            token_providers=[TestSubclass])
        self.assertIsNone(should_be_none)