【问题标题】:Unit tests mocks fails on rest API requests in Python单元测试模拟在 Python 中的 rest API 请求上失败
【发布时间】:2020-11-23 15:27:39
【问题描述】:

您好,我是单元测试的新手,我正在研究 mocks 和 pytest。我正在尝试对两个 rest api 请求进行单元测试,其中 GET 请求检查 API 中是否不存在某个项目以及它是否不创建它与 POST 请求并创建一个文件夹,否则如果它存在只是创建一个文件夹。

我尝试使用Mocker(),但当我尝试模拟GET 请求时,我被困在AttributeError: Mocker 上。

这是我要测试的代码:


   client = requests.session()
    # get item by name
    response = client.get(
        f"https://url.com/rest/item/info?name=test_item",
        auth=username, password),
    )

    if (
        response.status_code == 200
        and response.json()["status"]
        == "Item doesn't exist!"
    ):
        logging.info(f"Creating item")
        client.post(
            "https://url.com/rest/item/create?name=test_item",
            auth=username, password),
        )
        # directory creation
        dir_make = "mkdir -p test_item/temperature"
        exec_cmd(dir_make)

    elif response.status_code == 200 and response.json()["status"]=="OK":
        # directory creation
        dir_make = "mkdir -p test_item/temperature"
        exec_cmd(dir_make)

这是以AttributeError 失败的单元测试:

def test_existing_item(requests_mock, monkeypatch):
    with requests_mock.Mocker() as mock:
        mock.get("https://url.com/rest/item/info?name=test_item", text="OK")

        resp = requests.get("https://url.com/rest/item/info?name=test_item")
        assert resp.text == "OK"

编辑:测试未找到项目和 POST 模拟。似乎它没有为else 语句添加覆盖范围。如果该项目存在并且在这种情况下只需要添加文件夹,如何测试?

编辑 2:添加了 elif 语句而不是 else 和 2 个单独的测试,仍然是一个 test_existing_items() 不包括 elif 语句......在这种情况下我做错了什么?

def test_existing_item(monkeypatch):
    with requests_mock.Mocker() as mock_request:
        mock_request.get(requests_mock.ANY, text="success!")
        resp = requests.get(
            "https://url.com/rest/item/info?name=test_item",
            auth=("mock_username", "mock_password"),
        )
        if resp.status_code == 200 and resp.json()["status"] == "OK":
            dir_make = "mkdir -p test_item/temperature"
            exec_cmd(dir_make)


    encoded_auth = b64encode(b"mock_username:mock_password").decode("ascii")

    assert mock_request.last_request.headers["Authorization"] == f"Basic {encoded_auth}"


def test_post_item(monkeypatch):
    with requests_mock.Mocker() as mock_request:
        mock_request.get(requests_mock.ANY, text="success!")
        resp = requests.get(
            "https://url.com/rest/item/info?name=test_item",
            auth=("mock_username", "mock_password"),
        )

        if resp.status_code == 200 and resp.json()["status"] == "ERROR":
            mock_request.get(requests_mock.ANY, text="success!")
            requests.post(
                "https://url.com/rest/item/create?name=test_item",
                auth=("mock_username", "mock_password"),
            )

        dir_make = "mkdir -p test_item/temperature"
        exec_cmd(dir_make)


    encoded_auth = b64encode(b"mock_username:mock_password").decode("ascii")

    assert mock_request.last_request.headers["Authorization"] == f"Basic {encoded_auth}"

我不熟悉单元测试,所以如果能对这段代码进行单元测试,我们将不胜感激。

【问题讨论】:

    标签: python unit-testing mocking pytest


    【解决方案1】:
    import requests
    import requests_mock
    
    
    def test_existing_item(monkeypatch):
        with requests_mock.Mocker() as mock:
            mock.get("https://url.com/rest/item/info?name=test_item", text="OK")
    
            resp = requests.get("https://url.com/rest/item/info?name=test_item")
            assert resp.text == "OK"
    

    不要将requests_mock 作为参数传递,pytest 应该可以正常工作。

    编辑:

    至于您的编辑:

    似乎它没有为 else 语句添加覆盖范围。如果该项目存在并且在这种情况下只需要添加文件夹,如何测试?

    那是因为您的if 条件始终为真,因此它永远不会访问else 语句下方的代码。你的第二个问题我不太清楚,但我相信你想写几个测试,一个是你的if 语句,一个是你的else 语句。根据经验,如果您在测试中需要条件逻辑,您就会遇到一个问题:要么每次运行测试时一切都应该按照您的意愿进行,要么您应该按照您的意愿中止并让测试失败代码在每次运行时都具有完全相同的行为 - 以及扩展的测试。

    【讨论】:

    • @JohnyMostoq 如果您将我发送的代码中的.get() 调用替换为.post() 调用,它也同样有效。如果这还不足以测试您的代码,那么我想看看您在发送的代码上运行的测试
    • @JohnyMostoq 我编辑了我的评论。我希望这回答了你的问题
    • 我按照你的建议做了,分成 2 个测试,我对同一段代码得到了相同的结果(没有覆盖,只要项目存在)......我用分离的测试更新了问题和代码的变化。我并没有完全理解您所说的“如果您在测试中需要条件逻辑,那么您就有问题”是什么意思,在单元测试中设置条件是一种不好的做法吗?
    • @JohnyMostoq 我想这是一个见仁见智的问题,但我觉得大多数人会称之为不好的做法。测试的目的是确保代码以某种方式运行并返回某个值。如果你有条件逻辑,它的行为或输出可能会在多次运行时发生变化,即使它每次都以相同的方式调用——这意味着你需要重构代码以防止这种情况发生——或者永远不会输入一个条件,所以如果如果您希望执行两段代码(每个分支一个),则需要将其拆分为两个测试,都需要事先相应地修改环境。
    • @JohnyMostoq 至于你的主要问题,他们在你的机器上失败了吗?以及如何检测覆盖率?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-28
    • 1970-01-01
    • 1970-01-01
    • 2012-07-09
    • 2019-11-19
    相关资源
    最近更新 更多