2017-04-07 63 views
0

如何在同一个文件中修补与被测试的类相同的类,该类是在测试开始之前初始化的?

这是我测试(总结)文件(common.py)(请注意本在很大程度上从原来的问题修改,包括我错误地省略掉的细节。)。它包含一个装饰器(派生自Decorum library),该装饰器调用另一个对象(A)上的类方法:我想修补A,因为该代码使得我没有测试的外部调用。

from decorum import Decorum 


class A: 
    @classmethod 
    def c(cls): 
     pass 


class ClassyDecorum(Decorum): 
    """Hack to allow decorated instance methods of a class object to run with decorators. 
    Replace this once Decorum 1.0.4+ comes out. 
    """ 

    def __get__(self, instance, owner): 
     from functools import partial 
     return partial(self.call, instance) 


class B(Decorum): 

    def __init__(self, *args, **kwargs): 
     super().__init__(*args, **kwargs) 

    def init(self, *args, **kwargs): 
     A.c() 
     return super().init(*args, **kwargs) 

我想在我的单元测试@patchA,隔离和检查B.d()的功能。这是我的单元测试(位于test/test_common.py):

class BDecoratedClass(MagicMock): 

    @B 
    def dummy_func(self): 
     return "Success" 

class TestB(TestCase): 
    @patch('unittest_experiment.A', autospec=True) 
    def test_d(self, mock_a): 
     b = BDecoratedClass() 
     b.dummy_func() 
     mock_a.c.assert_called_once_with() # Fails 

调试上面,我看到A实际上从来不嘲笑:代码进行到A的代码,因此它是有道理的,mock_a不会被调用,并因此断言失败。不过,我想正确地使用猴子补丁A。如果我是猴子修补存在于common.py中的导入,但是显然不是该类是在那里定义的,则此方法有效?

注意,我认为这是可能的一个问题,即我打补丁,这是@patch('common.A', autospec=True)应该更可能是这样@patch('where.python.actually.finds.A.when.B.calls.A', autospec=True)。但我很不清楚如何确定是否属实,如果是这样,那么正确的路径是什么。例如,@patch('BDecorated.common.A', autospec=True)不起作用。

+0

@wim原始示例代码太简化了。我的错。我已经更新了一个适当的最小,可测试,可验证的例子。 –

+0

这听起来像你有某种导入古怪,你没有向我们展示。例如,如果'A'实际上是在一个不同的文件中定义的,而'from'被导入的,或者如果你已经做出了包中的一个常见错误,并且最终导致相同的文件被导入为两个模块。 – user2357112

+1

什么是'b.d'?我没有看到任何这样的方法。 – user2357112

回答

0

感谢@user2357112,我到达了这个解决方案。警告:我不知道这是标准还是“最佳”的做法,但似乎有效。

首先,将BDecoratedClass移动到它自己的文件test/dummy.py。然后测试改成这样:

class TestB(TestCase): 
    @patch('common.A', autospec=True) 
    def test_d(self, mock_a): 
     from test.dummy import BDecoratedClass 

     b = BDecoratedClass() 
     b.dummy_func() 
     mock_a.c.assert_called_once_with() # Succeeds 

这迫使执行正在装修前的哑类的进口补丁。这有点奇怪,因为导入是在函数内部,但对于看起来很好的测试。

更大买者

这个只适用于进口的东西从哪里模块,在这种情况下,从BDecoratedClass进口的第一次考验。在那个时候,班上的其他所有东西都被加载了,不能修补。

相关问题