在 python 类的任何实例上模拟方法 [英] Mocking out methods on any instance of a python class

查看:34
本文介绍了在 python 类的任何实例上模拟方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在生产代码中模拟某个类的任何实例上的方法,以便于测试.Python 中是否有任何库可以促进这一点?

I want to mock out methods on any instance of some class in the production code in order to facilitate testing. Is there any library in Python which could facilitate this?

基本上,我想做以下事情,但是在 Python 中(以下代码是 Ruby,使用 Mocha 库):

Basically, I want to do the following, but in Python (the following code is Ruby, using the Mocha library):

  def test_stubbing_an_instance_method_on_all_instances_of_a_class
    Product.any_instance.stubs(:name).returns('stubbed_name')
    assert_equal 'stubbed_name', SomeClassThatUsesProduct.get_new_product_name
  end

上面要注意的重要一点是,我需要在类级别模拟它,因为我实际上需要模拟我正在测试的事物创建的实例上的方法.

The important thing to note from above is that I need to mock it out on the class level, since I'm actually need to mock out methods on an instance created by the thing I'm testing.

用例:

我有一个 QueryMaker 类,它在 RemoteAPI 的实例上调用一个方法.我想模拟 RemoteAPI.get_data_from_remote_server 方法来返回一些常量.我如何在测试中执行此操作,而不必在 RemoteAPI 代码中添加特殊情况来检查它在什么环境中运行.

I have a class QueryMaker which calls a method on an instance of RemoteAPI. I want to mock out the RemoteAPI.get_data_from_remote_server method to return some constant. How do I do this inside a test without having to put a special case within the RemoteAPI code to check for what environment it's running in.

我想要的行动示例:

# a.py
class A(object):
    def foo(self):
        return "A's foo"

# b.py
from a import A

class B(object):
    def bar(self):
        x = A()
        return x.foo()

# test.py
from a import A
from b import B

def new_foo(self):
    return "New foo"

A.foo = new_foo

y = B()
if y.bar() == "New foo":
    print "Success!"

推荐答案

最简单的方法可能是使用类方法.您确实应该使用实例方法,但创建这些方法很痛苦,而有一个内置函数可以创建类方法.使用类方法,您的存根将获得对类(而不是实例)的引用作为第一个参数,但由于它是一个存根,这可能无关紧要.所以:

Easiest way is probably to use a class method. You really should use an instance method, but it's a pain to create those, whereas there's a built-in function that creates a class method. With a class method, your stub will get a reference to the class (rather than the instance) as the first argument, but since it's a stub this probably doesn't matter. So:

Product.name = classmethod(lambda cls: "stubbed_name")

请注意,lambda 的签名必须与您要替换的方法的签名相匹配.此外,当然,由于 Python(如 Ruby)是一种动态语言,因此不能保证在您接触实例之前不会有人将您的存根方法切换为其他东西,尽管我希望您很快就会知道如果发生这种情况.

Note that the signature of the lambda must match the signature of the method you're replacing. Also, of course, since Python (like Ruby) is a dynamic language, there is no guarantee that someone won't switch out your stubbed method for something else before you get your hands on the instance, though I expect you will know pretty quickly if that happens.

在进一步调查中,您可以省略classmethod():

On further investigation, you can leave out the classmethod():

Product.name = lambda self: "stubbed_name"

我试图尽可能地保留原始方法的行为,但看起来实际上并没有必要(无论如何,并没有像我希望的那样保留行为).

I was trying to preserve the original method's behavior as closely as possible, but it looks like it's not actually necessary (and doesn't preserve the behavior as I'd hoped, anyhow).

这篇关于在 python 类的任何实例上模拟方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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