【问题标题】:How can I mock sqlite3.Cursor我如何模拟 sqlite3.Cursor
【发布时间】:2017-07-21 06:50:53
【问题描述】:

我一直在努力弄清楚如何模拟 sqlite3.Cursor 类,特别是 fetchall 方法。

考虑以下代码示例

import sqlite3

from mock import Mock, patch
from nose.tools import assert_false


class Foo:
    def check_name(name):
        conn = sqlite3.connect('temp.db')
        c = conn.cursor()
        c.execute('SELECT * FROM foo where name = ?', name)
        if len(c.fetchall()) > 0:
            return True
        return False


@patch('sqlite3.Cursor.fetchall', Mock(return_value=['John', 'Bob']))
def test_foo():
    foo = Foo()
    assert_false(foo.check_name('Cane'))

运行nosetests 不会出现有趣的错误

E
======================================================================
ERROR: temp.test_foo
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/koddsson/.virtualenvs/temp/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/home/koddsson/.virtualenvs/temp/lib/python2.7/site-packages/mock.py", line 1214, in patched
    patching.__exit__(*exc_info)
  File "/home/koddsson/.virtualenvs/temp/lib/python2.7/site-packages/mock.py", line 1379, in __exit__
    setattr(self.target, self.attribute, self.temp_original)
TypeError: can't set attributes of built-in/extension type 'sqlite3.Cursor'

----------------------------------------------------------------------
Ran 1 test in 0.002s

FAILED (errors=1)

我应该不能模拟 fetchall 方法还是我做错了什么?

【问题讨论】:

标签: python unit-testing sqlite mocking nose


【解决方案1】:

我会采取修补你模块中导入的 sqlite3 的方法,然后从那里开始工作。

假设您的模块名为what.py

我会修补 what.sqlite3,然后模拟 .connect().cursor().fetchall 的返回值。

这是一个更完整的例子:

from mock import patch
from nose.tools import assert_true, assert_false

from what import Foo

def test_existing_name():
    with patch('what.sqlite3') as mocksql:
        mocksql.connect().cursor().fetchall.return_value = ['John', 'Bob']
        foo = Foo()
        assert_true(foo.check_name('John'))

【讨论】:

    【解决方案2】:

    我找到了一种在我的测试中模拟 sqlite3.Cursor 的方法:

    cursor = MagicMock(Cursor)
    cursor.fetchall.return_value = [{'column1': 'hello', 'column2': 'world'}]
    

    我是 python 的新手,但这是我在 Java 中的做法。

    【讨论】:

      【解决方案3】:

      您不能模拟所有内容,而且数据库特别棘手。我经常发现正确的做法(尤其是使用 Sqlite,因为它非常简单)是使用模拟数据加载测试数据库并在测试中使用它(即夹具)。毕竟,您真正需要测试的是您的代码是否正确访问和查询数据库。

      在这样的测试中,您通常试图回答的问题是“如果数据库中有 X 数据并且我执行查询 Y,该查询是否像我预期的那样返回 Z”,或者更高级别的“如果我将参数 X 传递给我的方法,它是否返回值 Z(基于从数据库中获取 Y)。”

      在您的示例中,真正的问题是“SELECT * FROM foo where name = ? 是此方法中的正确查询吗?”但如果你嘲笑响应,你就不会回答它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-09-14
        • 2015-07-29
        • 1970-01-01
        • 1970-01-01
        • 2016-06-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多