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

Phi*_*mer 6 json mocking python-3.x

我正在尝试进行单元测试,以验证从 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"]
Run Code Online (Sandbox Code Playgroud)

这是测试:

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")
Run Code Online (Sandbox Code Playgroud)

但是,当我运行测试时,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"]
Run Code Online (Sandbox Code Playgroud)

我不一定介意以这种形式保留我的代码,但我想了解我的测试中是否有错误,这将使我的函数保持其原始形式。

堆栈跟踪:

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)
Run Code Online (Sandbox Code Playgroud)

j4z*_*cat 8

我遇到了同样的问题,并通过模拟 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 ) ) 
Run Code Online (Sandbox Code Playgroud)

结果:

{'foo': 'bar'}
Run Code Online (Sandbox Code Playgroud)