pytest-minio-mock

Introducing pytest-minio-mock

As head of engineering professionally and as a contributor to Open Source projects, I am involved in several WebApp projects, where I put a large emphasis on code quality, smooth CI/CD pipelines as part of my dedication to DevOps principles. Some of the projects involves interactions with S3 storage via the Minio package for python. Writing unit tests for functions using the Minio client is essential and should not involve interactive with an actual S3 storage service. Against my expectations, I could not find any pytest plugin that mocks Minio().

After writing and reviewing some unit tests for interactions with the minio client, I though I had a good concept for a first version of a pytest plugin, that provides a fixture called minio-mock that mocks Minio() client created after the declaration of the minio-mock fixture. The result was the package pytest-minio-mock that I published on pypi.org under: https://pypi.org/project/pytest-minio-mock/. and you can find the source code under: https://github.com/oussjarrousse/pytest-minio-mock.

The plugin is small, not fancy and is not yet fully featured, but it is useful for the basics, and I hope you find it useful to.

The Plugin Design

The plugin code resides in the plugin.py module: https://github.com/oussjarrousse/pytest-minio-mock/blob/main/pytest_minio_mock/plugin.py where the main fixture minio-mock is defined as:

@pytest.fixture
def minio_mock(mocker, minio_mock_servers):
    def minio_mock_init(
        cls,
        *args,
        **kwargs,
    ):
        client = MockMinioClient(*args, **kwargs)
        client._connect(minio_mock_servers)
        return client

    patched = mocker.patch.object(Minio, "__new__", new=minio_mock_init)
    yield patched

Here, the mocker fixture is used to patch the Minio class and override the __new__() function, and replace it with the minio_mock_init() function that is defined within the fixture body.

When a Minio object is created, the function minio_mock_init() is called that creates a instance of the MockMinioClient class, and return the newly created instance… as in:

# will call __new__() of Minio that has been mocked to call minio_mock_init()
client = Minio()  
assert isinstance(client, MockMinioClient)

The MockMinioClient class provide an interface that is identical to the Minio class, but instead of interacting with an actual server, it interacts internally with a Server object that stores objects in memory.

The Server object provides persistency of buckets and objects between consecutive initiations of Minio instances. If the server object was destroyed, buckets and objects will also be destroyed and a consecutive initiation of Minio() client will not be able to retrieve buckets or objects.

Final words

The plugin is still at its early days and I am sure many features are still missing.
If you find it useful give the github repository a star, so that I know you are out there.

Some additional info:
Download stats of pytest-minio-mock: https://pypistats.org/packages/pytest-minio-mock
Reverse dependency of pytest-minio-mock: https://www.wheelodex.org/projects/pytest-minio-mock/rdepends/