Skip to content

Commit

Permalink
Patch uvicorn.run with pytest-mock
Browse files Browse the repository at this point in the history
https://github.com/pytest-dev/pytest-mock
https://docs.python.org/3/library/unittest.mock.html#where-to-patch

All unit tests pass, but when running Uvicorn, tests don't finish until
a manual keyboard interrupt is passed (`^C`).

```text
pytest
....................^C.^C.^C..........x.........                  [100%]
41 passed, 1 xfailed in 7.18s

pytest tests/test_start.py::TestStartServer::test_start_server_uvicorn \
  -vv
========================= test session starts =========================
platform darwin -- Python 3.8.5, pytest-6.0.1, py-1.9.0, pluggy-0.13.1
-- /Users/brendon/dev/inboard/.venv/bin/python3
cachedir: .pytest_cache
rootdir: /Users/brendon/dev/inboard, configfile: pyproject.toml
plugins: mock-3.3.1
collected 3 items

tests/test_start.py::TestStartServer::test_start_server_uvicorn[inboard
.app.base.main:app] ^CPASSED [ 33%]
tests/test_start.py::TestStartServer::test_start_server_uvicorn[inboard
.app.fastapibase.main:app] ^CPASSED [ 66%]
tests/test_start.py::TestStartServer::test_start_server_uvicorn[inboard
.app.starlettebase.main:app] ^CPASSED [100%]

========================== 3 passed in 9.96s ==========================
```

I initially considered implementing a context manager to stop the server
after a certain amount of time, but found it easier to allow pytest-mock
to automatically manage context. As the pytest-mock README says,

> The purpose of this plugin is to make the use of context managers and
> function decorators for mocking unnecessary.

I initially had `mocker.patch("inboard.start.start_server")`, but wasn't
able to check log messages. The solution was to use `mocker.patch` for
`uvicorn.run()`, not `inboard.start.start_server()`.

```py
class TestStartServer:
    """Start Uvicorn and Gunicorn servers using the method in `start.py`
    ---
    """

    @pytest.mark.parametrize(
        "app_module",
        [
            "inboard.app.base.main:app",
            "inboard.app.fastapibase.main:app",
            "inboard.app.starlettebase.main:app",
        ],
    )
    def test_start_server_uvicorn(
        self,
        app_module: str,
        logging_conf_dict: Dict[str, Any],
        mock_logger: logging.Logger,
        mocker: MockerFixture,
        monkeypatch: MonkeyPatch,
    ) -> None:
        """Test `start.start_server` with Uvicorn."""
        monkeypatch.setenv("LOG_FORMAT", "uvicorn")
        monkeypatch.setenv("LOG_LEVEL", "debug")
        monkeypatch.setenv("PROCESS_MANAGER", "uvicorn")
        assert os.getenv("LOG_FORMAT") == "uvicorn"
        assert os.getenv("LOG_LEVEL") == "debug"
        assert os.getenv("PROCESS_MANAGER") == "uvicorn"
        # this works
        mocker.patch("uvicorn.run", autospec=True)
        start.start_server(
            str(os.getenv("PROCESS_MANAGER")),
            app_module=app_module,
            logger=mock_logger,
            logging_conf_dict=logging_conf_dict,
        )
        mock_logger.debug.assert_called_once_with(
            "Running Uvicorn without Gunicorn."
        )
        # this doesn't work
        mock_start_server = mocker.patch(
            "inboard.start.start_server", autospec=True
        )
        mock_start_server.assert_called_once_with(
            "uvicorn",
            app_module=app_module,
            logger=mock_logger,
            logging_conf_dict=logging_conf_dict,
        )

```
  • Loading branch information
br3ndonland committed Sep 7, 2020
1 parent 735618a commit 3906b3d
Showing 1 changed file with 1 addition and 1 deletion.
2 changes: 1 addition & 1 deletion tests/test_start.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ def test_start_server_uvicorn(
assert os.getenv("LOG_FORMAT") == "uvicorn"
assert os.getenv("LOG_LEVEL") == "debug"
assert os.getenv("PROCESS_MANAGER") == "uvicorn"
# TODO: need to send interrupt to stop server. Try with a context manager?
mocker.patch("uvicorn.run", autospec=True)
start.start_server(
str(os.getenv("PROCESS_MANAGER")),
app_module=app_module,
Expand Down

0 comments on commit 3906b3d

Please sign in to comment.