如何在json.load()中使用mock_open?

时间:2018-07-02 14:49:58

标签: json python-3.x mocking

我正在尝试进行单元测试,以验证从JSON编码文件中读取凭证的功能。由于凭据本身不是固定的,因此单元测试需要提供一些凭据,然后测试它们是否已正确检索。

这是凭证功能:

def read_credentials():
    basedir = os.path.dirname(__file__)
    with open(os.path.join(basedir, "authentication.json")) as f:
        data = json.load(f)
        return data["bot_name"], data["bot_password"]

这是测试:

def test_credentials(self):
    with patch("builtins.open", mock_open(
        read_data='{"bot_name": "name", "bot_password": "password"}\n'
    )):
        name, password = shared.read_credentials()
    self.assertEqual(name, "name")
    self.assertEqual(password, "password")

但是,当我运行测试时,json代码会因解码错误而崩溃。看一下json代码本身,我正在努力查看为什么模拟测试失败,因为json.load(f)只是调用f.read()然后调用json.loads()。

实际上,如果我将身份验证功能更改为以下内容,则单元测试有效:

def read_credentials():
    # Read the authentication file from the current directory and create a
    # HTTPBasicAuth object that can then be used for future calls.
    basedir = os.path.dirname(__file__)
    with open(os.path.join(basedir, "authentication.json")) as f:
        content = f.read()
        data = json.loads(content)
        return data["bot_name"], data["bot_password"]

我不必介意以这种形式保留我的代码,但是我想了解一下我的测试中是否有什么错误可以使我的功能保持其原始形式。

堆栈跟踪:

Traceback (most recent call last):
  File "test_shared.py", line 56, in test_credentials
shared.read_credentials()
  File "shared.py", line 60, in read_credentials
data = json.loads(content)
  File "/home/philip/.local/share/virtualenvs/atlassian-webhook-basic-3gOncDp4/lib/python3.6/site-packages/flask/json/__init__.py", line 205, in loads
return _json.loads(s, **kwargs)
  File "/usr/lib/python3.6/json/__init__.py", line 367, in loads
return cls(**kw).decode(s)
  File "/usr/lib/python3.6/json/decoder.py", line 339, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python3.6/json/decoder.py", line 357, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

1 个答案:

答案 0 :(得分:1)

我遇到了同样的问题,并通过模拟json.load和Builtins.open来解决:

import json
from unittest.mock import patch, MagicMock

# I don't care about the actual open
p1 = patch( "builtins.open", MagicMock() )

m = MagicMock( side_effect = [ { "foo": "bar" } ] )
p2 = patch( "json.load", m )

with p1 as p_open:
    with p2 as p_json_load:
        f = open( "filename" )
        print( json.load( f ) ) 

结果:

{'foo': 'bar'}