如何用模拟补丁模块的内部功能? [英] How to patch a module's internal functions with mock?

查看:76
本文介绍了如何用模拟补丁模块的内部功能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

内部函数"是指在定义该模块的同一模块中调用的函数.

By "internal function", I mean a function that is called from within the same module it is defined in.

我正在使用 mock 库,尤其是patch 装饰器.它们是Django单元测试,但这应适用于所有python测试.

I am using the mock library, specifically the patch decorators, in my unit tests. They're Django unit tests, but this should apply to any python tests.

我有一个具有多个功能的模块,其中许多功能相互调用.例如(虚拟代码,请忽略缺少decimal.Decimal):

I have one module with several functions, many of which call each other. For example (fictitious code, ignore the lack of decimal.Decimal):

TAX_LOCATION = 'StateName, United States'

def add_tax(price, user):
    tax = 0
    if TAX_LOCATION == 'StateName, UnitedStates':
        tax = price * .75
    return (tax, price+tax)

def build_cart(...):
    # build a cart object for `user`
    tax, price = add_tax(cart.total, cart.user)
    return cart

这些是更深层次的调用链(func1-> func2-> build_cart-> add_tax)的一部分,所有这些都在同一模块中.

These are part of a deeper calling chain (func1 -> func2 -> build_cart -> add_tax), all of which are in the same module.

在单元测试中,我想禁用税收以获得一致的结果.正如我所看到的,我的两个选择是:1)修补TAX_LOCATION(用空字符串表示),以便add_tax实际上不做任何事情;或2)修补add_tax以简单地返回(0,价格).

In my unit tests, I'd like to disable taxes to get consistent results. As I see it, my two options are 1) patch out TAX_LOCATION (with an empty string, say) so that add_tax doesn't actually do anything or 2) patch out add_tax to simply return (0, price).

但是,当我尝试修补其中任何一个修补程序时,该修补程序似乎都可以在外部工作(我可以将已修补的部分导入测试中并打印出来,以获得期望值),但是似乎对内部没有任何影响(结果我从代码中获得的行为就像未应用补丁一样.

However, when I try to patch either of these the patch seems to work externally (I can import the patched part inside the test and print it out, getting expected values), but seems to have no effect internally (the results I get from the code behave as if the patch were not applied).

我的测试是这样的(再次是虚构的代码):

My tests are like this (again, fictitious code):

from mock import patch
from django.test import TestCase

class MyTests(TestCase):

    @patch('mymodule.TAX_LOCATION', '')
    def test_tax_location(self):
        import mymodule
        print mymodule.TAX_LOCATION # ''
        mymodule.func1()
        self.assertEqual(cart.total, original_price) # fails, tax applied

    @patch('mymodule.add_tax', lambda p, u: (0, p))
    def test_tax_location(self):
        import mymodule
        print mymodule.add_tax(50, None) # (0, 50)
        mymodule.func1()
        self.assertEqual(cart.total, original_price) # fails, tax applied

有人知道模拟程序是否有可能修补内部使用的函数,还是我不走运?

Does anyone know if it's possible for mock to patch out functions used internally like this, or am I out of luck?

推荐答案

答案:清理过时的进口商品

@patch('mymodule.TAX_LOCATION', '')确实确实对补丁进行了修补,但是由于我们当时的导入非常杂乱-有时我们导入了mymodule.build_cart,有时我们导入了project.mymodule.build_cart-完整"导入的实例未在以下位置进行修补全部.无论如何,如果不明确告知,就无法期望Mock知道这两个单独的导入路径.

@patch('mymodule.TAX_LOCATION', '') did indeed patch things appropriately, but since our imports at the time were very haphazard -- sometimes we imported mymodule.build_cart, sometimes we imported project.mymodule.build_cart -- instances of the "full" import were not patched at all. Mock couldn't be expected to know about the two separate import paths... without being told explicitly, anyway.

自那以后,我们就在更长的路径上对所有进口进行了标准化,现在情况变得更加好了.

We've since standardized all our imports on the longer path, and things behave much more nicely now.

这篇关于如何用模拟补丁模块的内部功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆