在Python中使用mock模拟多个响应

1 投票
1 回答
1069 浏览
提问于 2025-04-18 12:33

我正在尝试为我用 mock 写的 Rest 客户端编写单元测试。

假设这个类叫做 Foo,它有两个方法:get_foo()get_bar()

这是我的测试类:

fake_foo_response= 'foo'
class FooTestCase(unittest.TestCase):
  def setUp(self):
    self.patcher = patch('foo', fake_foo_response)
    self.patcher.start()
    self.foo = Foo()

  def tearDown(self):
    self.patcher.stop()

  def test_get_foo(self):
    response = self.foo.get_foo()
    self.assertEqual(response,'foo')

我基本上是参考了这个教程才做到的:http://seminar.io/2013/09/27/testing-your-rest-client-in-python/

但是现在,我也想测试一下 bar,应该怎么用这种方法来测试 bar 呢?谢谢!

1 个回答

0

你可能会发现使用 MagicMocks 比使用补丁更简单,下面这种方式应该会对你有帮助:

from mock import MagicMock

fake_foo_response = 'foo'
fake_bar_response = 'bar'

class FooTestCase(unittest.TestCase):

    def setUp(self):
        self.foo = Foo()
        self.foo.get_foo = MagicMock(return_value=fake_foo_response)
        self.foo.get_bar = MagicMock(return_value=fake_bar_response)

    def test_get_foo(self):
        response = self.foo.get_foo()
        self.assertEqual(fake_foo_response, response)

    def test_get_bar(self):
        response = self.foo.get_bar()
        self.assertEqual(fake_bar_response, response)

不过,我觉得你需要看看你在测试的到底是什么。在你的例子中,你实际上只是:

  • 创建了一个 Foo 对象的实例。
  • 把一个函数的返回值改成了特定的值。
  • 调用了这个被改过的函数(也就是不是原来的函数),并检查返回值。

你实际上并没有在测试 get_foo 函数,因此你上面展示的测试并没有什么实际意义。不过,你这里展示的技术对于测试像 REST 客户端这样的东西非常有用(因为它需要调用测试单元外部的服务)。假设你真正的 get_foo 实现是这样的:

  1. 对输入参数进行一些处理
  2. 调用一个外部网址,并获取响应(这部分你想要模拟)
  3. 对响应进行一些处理,并可能返回一些东西给调用者

如果你要对这个函数进行单元测试,你应该写一个测试来测试 get_foo,并检查上面第 1 和第 3 点的行为,但对第 2 点进行补丁。这种补丁方式非常有价值,因为你可以用它来测试 get_foo,同时模拟掉单元外部的调用,例如:

class Foo:

    def get_foo(self, input):
        url_param = <do something with input>
        response = self._call_url(url_param)
        output = <do something with response>
        return output


class FooTestCase(unittest.TestCase):

    def setUp(self):
        self.foo = Foo()
        self.foo._call_url = MagicMock(return_value='some response')

    def test_get_foo(self):
        output = self.foo.get_foo('bar')
        self.assertEqual('ni', output)

现在,你可以使用补丁(通过 MagicMock)来测试你 get_foo 方法中的代码,而不需要依赖于调用单元外部的东西。

希望这对你有帮助。

撰写回答