如何为python单元测试提供模拟类方法?

时间:2016-07-26 00:53:01

标签: python unit-testing mocking

假设我有一个这样的课程。

   class SomeProductionProcess(CustomCachedSingleTon):

       def loaddata():
           """
           Uses an iterator over a large file in Production for the Data pipeline.
           """

           pass

现在在测试时我想改变loaddata()方法中的逻辑。这将是一个简单的自定义逻辑,不处理大数据。

我们如何使用Python Mock UnitTest框架在测试时提供loaddata()的自定义实现?

3 个答案:

答案 0 :(得分:14)

这是使用mock

执行此操作的简单方法
import mock


def new_loaddata(cls, *args, **kwargs):
    # Your custom testing override
    return 1


def test_SomeProductionProcess():
    with mock.patch.object(SomeProductionProcess, 'loaddata', new=new_loaddata):
        obj = SomeProductionProcess()
        obj.loaddata()  # This will call your mock method

如果您能够,我建议您使用pytest代替unittest模块。它使您的测试代码更加清晰,并减少了unittest.TestCase样式测试所带来的大量样板。

答案 1 :(得分:5)

要使用结构化return_value轻松模拟出类方法,可以使用unittest.mock.Mock

from unittest.mock import Mock

mockObject = SomeProductionProcess
mockObject.loaddata = Mock(return_value=True)

编辑:

由于您希望使用自定义实现模拟该方法,因此您可以创建一个自定义模拟方法对象,并在测试运行时替换原始方法。

def custom_method(*args, **kwargs):
    # do custom implementation

SomeProductionProcess.loaddata = custom_method

答案 2 :(得分:2)

假设您有一个名为 awesome.py 的模块,其中包含:

import time

class SomeProductionProcess(CustomCachedSingleTon):

    def loaddata(self):
        time.sleep(30) # simulating a long running process
        return 2

那么你模仿loaddata的单位测试看起来像这样:

import unittest

import awesome # your application module


class TestSomeProductionProcess(unittest.TestCase):
    """Example of direct monkey patching"""

    def test_loaddata(self):
        some_prod_proc = awesome.SomeProductionProcess()
        some_prod_proc.loaddata = lambda x: 2 # will return 2 every time called
        output = some_prod_proc.loaddata()
        expected = 2

        self.assertEqual(output, expected)

或者看起来像这样:

import unittest
from mock import patch

import awesome # your application module

class TestSomeProductionProcess(unittest.TestCase):
    """Example of using the mock.patch function"""

    @patch.object(awesome.SomeProductionProcess, 'loaddata')
    def test_loaddata(self, fake_loaddata):
        fake_loaddata.return_value = 2
        some_prod_proc = awesome.SomeProductionProcess()

        output = some_prod_proc.loaddata()
        expected = 2

        self.assertEqual(output, expected)

现在,当您运行测试时,loaddata对于这些测试用例不会花费30秒。