pytest:无法模拟我班级的 __init__ [英] pytest : Cannot mock __init__ of my class

查看:66
本文介绍了pytest:无法模拟我班级的 __init__的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义的 Db 类,它具有基本操作.我正在尝试围绕它编写测试 - 在我的班级的 __init__ 上我连接到我想避免的实际数据库(因为我只是在编写单元测试,不需要连接到实际数据库).

I am having a custom Db class, which has the basic operations. I am trying to write tests around it - on the __init__ of my class I am connecting to actual db which I want to avoid ( since I am just writing unit tests, no need to connect to the actual db ).

这是我的代码:

@mock.patch( 'mydb.Db' )
@pytest.mark.parametrize( "input,expected", [
    (
        {
            'key'   : "x" ,
            'value' : 5   ,
        } , 
        [  "x = 5" ]
    ) ,
    ])
def test_where_statement( mock_db, input, expected):
    mock_db.__init__.return_value = None
    assert expected == mock_db.where( input[ "key"] , input[ "value" ] )._condition_list

它在我将 return_value 设置为 None 的行失败 - 问题是:

It fails on the line where I set the return_value to None - issue is :

    def test_where_statement( mock_db, input, expected):
>       mock_db.__init__.return_value = None
E       AttributeError: 'instancemethod' object has no attribute 'return_value'

我只想模拟 init 函数,然后能够运行 where 函数(例如构建查询的 where 语句).

I want to mock only the init function and then be able to run the where function ( which builds the where statement of my query for example ).

我错过了什么?

推荐答案

AFAIK 你可以在这里有两种不同的方法.一种是直接用你的补丁模拟 __init__ 方法,它会按预期工作(原始的 __init__ 不会被调用).

AFAIK you can have two separate approaches here. One is to mock __init__ method directly with your patch, and it will work as expected (original __init__ would not be called).

@mock.patch('mydb.Db.__init__', return_value=None)

第二,使用您当前的方法,而不是将 None 值分配给 mock_db __init__ 方法(沿途不会被调用,因为对象已经是模拟的)将 return_value 分配给被调用的 mock_db获取 Db 类的实例(mock_db.return_value 应指向 Db 实例的模拟版本)或保持原样,如果您对更改默认模拟的行为不感兴趣get as 代码将被执行(AFAIR 在调用类以创建其实例时会自动创建一些 Mock 对象).

Second, with your current approach, instead of assigning None value to mock_db __init__ method (which would not be called along the way, as object is mock already) assign return_value to mock_db which is called to get an instance of the Db class (mock_db.return_value should point to mock version of your Db instance) or leave it as it is if you're not interested in changing behavior of default mock that you'd get as code would be executed (AFAIR when calling a class to create its instance some Mock object is created automatically).

您需要确保在适当的位置模拟 mydb.经验法则是模拟事物的导入位置而不是它们所在的位置.因此,换句话说,如果您想测试放置在具有 import mydb 的文件 my_package.my_module 中的代码,您需要修补 my_package.my_module.mydb.数据库.

You need to be sure that you mock mydb in proper location. The rule of thumb is to mock things where they are imported and not where they are located. So in other words, if you want to test code that is placed in file my_package.my_module that has import mydb you need to patch my_package.my_module.mydb.Db.

关于模拟的大量资源:解释 ELI5 模拟

应该突出的第一件事是我们使用 mock.patch 方法装饰器来模拟位于 mymodule.os 的对象,并将该模拟注入到我们的测试用例方法中.只模拟 os 本身而不是在 mymodule.os 中对它的引用不是更有意义吗?

One of the first things that should stick out is that we’re using the mock.patch method decorator to mock an object located at mymodule.os, and injecting that mock into our test case method. Wouldn’t it make more sense to just mock os itself, rather than the reference to it at mymodule.os?

嗯,在导入和管理模块方面,Python 有点像一条狡猾的蛇.在运行时, mymodule 模块有自己的 os,它被导入到模块中自己的本地范围.因此,如果我们模拟 os,我们将不会在 mymodule 模块中看到模拟的效果.不断重复的口头禅是:

Well, Python is somewhat of a sneaky snake when it comes to imports and managing modules. At runtime, the mymodule module has its own os which is imported into its own local scope in the module. Thus, if we mock os, we won’t see the effects of the mock in the mymodule module. The mantra to keep repeating is this:

模拟一个物品的使用地点,而不是它的来源.

Mock an item where it is used, not where it came from.

这篇关于pytest:无法模拟我班级的 __init__的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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