简体   繁体   English

如何在python单元测试中覆盖(而非修补)单个方法

[英]How to override (not patch) a single method in a python unit test

I've searched for hours. 我已经搜索了几个小时。 Can't find anyone even trying to do this. 甚至找不到试图这样做的人。 Hmmm.

I believe I have to override a single method within a class instance. 我相信我必须重写类实例中的单个方法。 I do not mean patch(return_value=) . 不是patch(return_value=) I need to make the method in question do something involving self . 我需要使所讨论的方法做一些涉及self事情。

I'll try to break it down. 我会尽力分解。 Liberally paraphrasing and including one of the many things I tried, which doesn't work ... 随意地改写并包括我尝试过的许多方法之一,这是行不通的...

class SetupClass(object):
    def set_some_stuff(self):
        data_list = functon_cannot_be_run_on_test_platform()
        self.something = data_list[0]
        self.something_else = data_list[1]

class UUT(object):
    self.config = SetupClass()
    assert self.config.something == 'foo'

class UnitTests(TestCase):

    @patch('SetupClass')
    def test_UUT(self, mock1):

        def WedgeClass(SetupClass):
            def set_some_stuff(self):
                self.something = 'foo'
                pass # I'm a Python newbie, in too deep

        wedge_class = WedgeClass()
        mock1.return_value = wedge_class # doesn't work. context errors

        uut = UUT() # <-- would crash here, because assert above

Assume that I cannot make changes to UUT or SetupClass . 假设我无法对UUTSetupClass进行更改。

Testing cannot even get off the ground because the assertion will fail, due to, SetupClass.functon_cannot_be_run_on_test_platform() . 测试甚至无法启动,因为断言将由于SetupClass.functon_cannot_be_run_on_test_platform()而失败。 Note that simply mocking SetupClass.functon_cannot_be_run_on_test_platform will not solve the problem, because reasons. 请注意 ,由于原因仅嘲笑SetupClass.functon_cannot_be_run_on_test_platform并不能解决问题。

ATM, I figure the only way to get around this mess is to somehow override SetupClass.set_some_stuff . 在ATM上,我认为避免这种混乱的唯一方法是以某种方式覆盖SetupClass.set_some_stuff I cannot simply mock the entire class, because UUT relies heavily on its other functionality as well. 我不能简单地模拟整个类,因为UUT非常依赖于其其他功能。 I need everything to work as is, except this one method and I need that method to be able to access, self in the same context as originally intend. 我需要一切都按原样工作,除了这个方法之外我还需要该方法能够在与最初意图相同的上下文中self访问。

I tried various things involving subclassing and mock.return_value etc. I'd rather not recall the pain that caused. 我尝试了各种涉及子类化和模拟.return_value等的事情。我宁愿不记得引起的痛苦。 :p :p

My kingdom for test-driven code in the first place! 我的王国首先是测试驱动的代码! This code contains a convolution of co-dependencies. 此代码包含一些相互依赖的卷积。 :-/ :-/

Apart from the multiple errors in the example code I wrote up off the top of my head at the cafe ... 除了示例代码中的多个错误外,我还在咖啡馆里写下了自己的头……

The problem was (mostly) that I was using return_value instead of side_effect to 'replace' the patched class with my own subclass. 问题是(主要是)我使用return_value而不是side_effect将修补的类替换为自己的子类。

My need, re-stated perhaps more clearly now, is to override a single method, set_some_stuff , in a class within the unit under test (UUT) but without mocking the class. 现在,我可能需要更清楚地set_some_stuff ,我的需要是在被测单元(UUT)中的类中重写单个方法set_some_stuffset_some_stuff该类。

The method issues several 'self.foo = bar' statements, which I want to change for testing purposes. 该方法发出多个“ self.foo = bar”语句,出于测试目的,我想对其进行更改。 Thus, mocking the method's (unused) return value is not enough ... and patch.object seems to lose class context, "'self' unknown" or the like. 因此,仅嘲笑该方法的(未使用的)返回值是不够的……并且patch.object似乎丢失了类上下文,“'自身'未知”等。

Finally , here is the working code, doing what I need ... 最后 ,这是工作代码,执行我需要做的...

import unittest
import mock

class SetupClass(object):
    def set_some_stuff(self):
        data_list = ['data not available', 'on test_platform'] # CRASH!
        self.something = data_list[0]
        self.something_else = data_list[1]

class UUT:
    def __init__(self):
        self.config = SetupClass()
        self.config.set_some_stuff()
        assert self.config.something == 'foo' # <-- used to crash before here ...
        self.got_here = True # ... but now the override method from
                             # WedgeClass is being used! :=)

"""
Subclass the original class, overriding just the method in question.  Then set
the subclass as the side_effect of the patched original, effectively replacing it.
"""
class WedgeClass(SetupClass):
    def set_some_stuff(self):
        self.something = 'foo'
        pass # I'm a Python newbie, in too deep

class UnitTests(unittest.TestCase):

    @mock.patch(__module__+'.SetupClass')
    def test_UUT(self, mock1):
        wedge_class = WedgeClass()
        mock1.side_effect = WedgeClass # <--- Ureka! 'side_effect' not 'return_value' was the ley!

        uut = UUT()
        self.assertTrue(uut.got_here)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM