pytest:不能模仿我班级的__init__

时间:2017-11-09 12:53:40

标签: python unit-testing pytest

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

这是我的代码:

@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的行上失败 - 问题是:

    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语句)。

我错过了什么?

1 个答案:

答案 0 :(得分:1)

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

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

其次,使用您当前的方法,而不是将None值赋给mock_db __init__方法(不会一直调用,因为对象已经是mock),将return_value分配给mock_db,调用它来获取实例Db类(mock_db.return_value应该指向你的Db实例的模拟版本)或保留原样,如果你对改变默认模拟的行为不感兴趣,你会得到代码就会执行时(AFAIR在调用类来创建其实例时,会自动创建一些Mock对象)。

编辑: 你需要确保你在适当的位置模拟mydb。经验法则是模拟它们被导入的地方而不是它们所在的位置。换句话说,如果您要测试放置在my_package.my_module文件import mydb中的代码,则需要修补my_package.my_module.mydb.Db

有关模拟的大量资源:ELI5 mocks explained

  

最重要的事情之一是我们使用mock.patch方法装饰器来模拟位于mymodule.os的对象,并将该mock注入我们的测试用例方法。仅仅模拟操作系统本身,而不是在mymodule.os上引用它是不是更有意义?

     

嗯,在进口和管理模块时,Python有点像偷偷摸摸的蛇。在运行时,mymodule模块有自己的操作系统,它被导入到模块中自己的本地范围。因此,如果我们模拟os,我们将不会在mymodule模块中看到mock的效果。   继续重复的口头禅是:

     
    

模拟使用它的项目,而不是它的来源。