Python模拟补丁os.environ和返回值

9cbw7uwe  于 2023-04-13  发布在  Python
关注(0)|答案(7)|浏览(170)

使用mock进行单元测试conn():
app.py

import mysql.connector
import os, urlparse

def conn():
    if "DATABASE_URL" in os.environ:
        url = urlparse(os.environ["DATABASE_URL"])
        g.db = mysql.connector.connect(
            user=url.username,
            password=url.password,
            host=url.hostname,
            database=url.path[1:],
        )
    else:
        return "Error"

test.py

def test_conn(self):
    with patch(app.mysql.connector) as mock_mysql:
        with patch(app.os.environ) as mock_environ:
            con()
            mock_mysql.connect.assert_callled_with("credentials")

错误:Assertionmock_mysql.connect.assert_called_with未被调用。
我相信这是因为'Database_url'不在我的补丁os.environ中,并且因为测试调用没有对mysql_mock. connect进行。
问题:
1.我需要做哪些更改才能使此测试代码正常工作?
1.我是否还必须修补urlparse

bihw5rsg

bihw5rsg1#

你可以尝试unittest.mock.patch.dict解决方案,只需要用dummy参数调用conn即可:

import mysql.connector
import os, urlparse
from unittest import mock

@mock.patch.dict(os.environ, {"DATABASE_URL": "mytemp"}, clear=True)  # why need clear=True explained here https://stackoverflow.com/a/67477901/248616
# If clear is true then the dictionary will be cleared before the new values are set.
def conn(mock_A):
    print os.environ["mytemp"]
    if "DATABASE_URL" in os.environ:
        url = urlparse(os.environ["DATABASE_URL"])
        g.db = mysql.connector.connect(
            user=url.username,
            password=url.password,
            host=url.hostname,
            database=url.path[1:],
        )
    else:
        return "Error"

或者如果你不想修改你的原始函数,试试这个解决方案:

import os
from unittest import mock

def func():
    print os.environ["mytemp"]

def test_func():
    k = mock.patch.dict(os.environ, {"mytemp": "mytemp"})
    k.start()
    func()
    k.stop()

test_func()
hpcdzsge

hpcdzsge2#

为此,我发现当你需要设置环境变量时,pytest's monkeypatch fixture会带来更好的代码:

def test_conn(monkeypatch):
    monkeypatch.setenv('DATABASE_URL', '<URL WITH CREDENTIAL PARAMETERS>')
    with patch(app.mysql.connector) as mock_mysql:
        conn()
    mock_mysql.connect.assert_called_with(<CREDENTIAL PARAMETERS>)
juzqafwq

juzqafwq3#

接受的答案是正确的。这里有一个装饰器@mockenv来做同样的事情。

def mockenv(**envvars):
    return mock.patch.dict(os.environ, envvars)

@mockenv(DATABASE_URL="foo", EMAIL="bar@gmail.com")
def test_something():
    assert os.getenv("DATABASE_URL") == "foo"
bvpmtnay

bvpmtnay4#

在我的用例中,我试图模拟没有设置环境变量。要做到这一点,请确保将clear=True添加到补丁中。

with patch.dict(os.environ, {}, clear=True):
    func()
bihw5rsg

bihw5rsg5#

在导入模块之前,在文件模拟环境的头部:

with patch.dict(os.environ, {'key': 'mock-value'}):
    import your.module
fhity93d

fhity93d6#

您还可以使用类似question中描述的modified_environ上下文管理器来设置/恢复环境变量。

with modified_environ(DATABASE_URL='mytemp'):
    func()
vpfxa7rd

vpfxa7rd7#

here的回答略有改进

@mock.patch.dict(os.environ, {"DATABASE_URL": "foo", "EMAIL": "bar@gmail.com"})
def test_something():
    assert os.getenv("DATABASE_URL") == "foo"

相关问题