'Unit test for pytest_collection_modifyitems python hook

I've implemented a custom logic to the pytest_collection_modifyitems(config, items). Basically it will just filter out some of the items/tests and run the selected ones, based on the given config.getoption parameter.

from unittest import mock
import pytest
from conftest import pytest_collection_modifyitems

def pytest_collection_modifyitems(config, items):
    selected_tests = config.getoption("selected_tests", default="")

    if selected_tests != "":
        tests_to_run = []

        for item in items:
            marker = item.get_closest_marker("test_case_id")
            if marker and marker.args and str(marker.args[0]) in selected_tests:
                tests_to_run.append(item)

        items[:] = tests_to_run

This is fine and dandy and it does the job. But I want to properly unit test this behavior. I want to see that the items list is updated at the end. I have a working unit test, but I'm interested how to improve the solution. It seems for me that I could have reduced the amount of Mocks somehow. I'm fairly new to python.

# fmt: off
test_data = [
    # selected_test_ids  available_test_ids  expected_test_ids
    # valid cases
    ("123",              [123, 456],         [123]),
    ("123, 456",         [123, 456, 789],    [123, 456]),

    # invalid cases
    ("",                 [321, 654],         [321, 654]),  # if there is no selection, run all tests by default
    ("564",              [111, 222],         [111, 222]),  # if the selection is invalid, run all tests by default
]
# fmt: on


@pytest.mark.parametrize("selected_test_ids, available_test_ids, expected_test_ids", test_data)
def test_pytest_collection_modifyitems(selected_test_ids, available_test_ids, expected_test_ids):
    def get_test_case_ids(items):
        return [item.get_closest_marker.return_value.args[0] for item in items]

    def get_mocked_items():
        mocked_items = list()
        for test_id in available_test_ids:
            # each test has its own marker associated, where the arg[0] attribute holds the value of the test_case_id
            mock_marker = mock.Mock()
            mock_marker.args = [test_id]

            # assign the created mock_marker to the get_closest_marker function
            mock_item = mock.Mock()
            mock_item.get_closest_marker.return_value = mock_marker

            mocked_items.append(mock_item)

        return mocked_items

    # mock config parameter and set up the "--run_selection" value
    mock_config = mock.Mock()
    mock_config.getoption.return_value = selected_test_ids

    # mock items parameter, which is a list of available tests
    mock_items = get_mocked_items()

    # Act.
    pytest_collection_modifyitems(mock_config, mock_items)

    # the pytest_collection_modifyitems updates the mocked items list, so
    # we need to extract the test IDs from the updated list
    assert get_test_case_ids(mock_items) == expected_test_ids




Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source