简体   繁体   English

我需要在 python 中模拟 docker 服务器进行单元测试

[英]I need to mock docker server for unit tests in python

I have developped a class that uses the docker library with我开发了一个使用 docker 库的类

self.client = docker.from_env(timeout=5, version="auto")

and as example:例如:

def run_container_in_background(self,application,branch,name_container,mount_dir):
    container =self.client.containers.run(image,command"bash",detach=True,name=name_container)

I need to make a unit test for this method so i need to mock the docker server.我需要为此方法进行单元测试,所以我需要模拟 docker 服务器。 So does anyoe have an idea how to mock it using python?那么有人知道如何使用 python 模拟它吗?

When I try to mock "self.client = docker.from_env(timeout=5, version="auto")"当我尝试模拟“self.client = docker.from_env(timeout=5, version="auto")”

self = <docker.api.client.APIClient object at 0x0EE644D0> self = <docker.api.client.APIClient 对象在 0x0EE644D0>

def _retrieve_server_version(self):
    try:
        return self.version(api_version=False)["ApiVersion"]
    except KeyError:
        raise DockerException(
            'Invalid response from docker daemon: key "ApiVersion"'
            ' is missing.'
        )
    except Exception as e:
        raise DockerException('Error while fetching server API version: 
{0}'.format(e))
E           docker.errors.DockerException: Error while fetching server API version: (2, 'CreateFile', 'Le fichier spécifié est introuvable.')

PS: the docker daemon is deactivate to reproduce the same issue i want to solve. PS:docker 守护进程被停用以重现我想要解决的相同问题。 Is there any way to solve the mocking problem to fix this issue?有没有办法解决模拟问题来解决这个问题?

You should probably refactor this class to take the Docker client as a parameter, rather than create its own.您可能应该重构此类以将 Docker 客户端作为参数,而不是创建自己的类。 In addition to supporting this testing setup, this will also help you do things like share connection pools between objects and avoid repeating some details like that timeout.除了支持此测试设置之外,这还将帮助您执行诸如在对象之间共享连接池并避免重复诸如超时之类的一些细节之类的事情。

class ObjectUnderTest:
  def __init__(self, client):
    self.client = client

  def run_container_in_background(self, application, branch, name_container, mount_dir):
    self.client...

def main():
  client = docker.from_env(timeout=5)
  obj = ObjectUnderTest(client)

Having done this, you can create any object you want and pass it in as the client parameter.完成此操作后,您可以创建所需的任何对象并将其作为client参数传入。 Especially since Python is generally dynamically typed, you can use your mock object in place of the real client, just so long as the object you create has the same "shape" as the calling code expects.特别是因为 Python 通常是动态类型的,您可以使用模拟对象代替真实客户端,只要您创建的对象具有与调用代码期望的相同的“形状”。

class MockContainer:
  '''A fake Docker API container object.'''
  def __init__(self, *args, **kwargs):
    self.args = args
    self.kwargs = kwargs

class MockContainersApi:
  '''A fake Docker API with containers calls.'''
  def run(self, *args, **kwargs):
    return MockContainer(*args, **kwargs)

class MockDockerApi:
  '''A fake Docker API.'''
  def __init__(self):
    self.containers = MockContainersApi()

def test_run_container():
  client = MockDockerApi()
  obj = ObjectUnderTest(client)
  container = obj.run_container_in_background(...)
  assert container.kwargs['detach'] == True

(Also consider how much your application needs to call the Docker API directly, and if it could be refactored to use other technology. As you note in this question, the Docker API is complex and the required testing approach isn't simple. Since you can bind-mount an arbitrary host directory into a container, it's also very easy to get a container running as root that can write to the host's /etc directory, and thereby root the whole host.) (还要考虑您的应用程序需要多少直接调用 Docker API,是否可以重构以使用其他技术。正如您在此问题中所指出的,Docker API 很复杂,所需的测试方法并不简单。由于您可以将任意主机目录绑定挂载到容器中,也很容易让容器以 root 身份运行,可以写入主机的/etc目录,从而使整个主机成为 root。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM