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

Vin*_*eel 15 python unit-testing mocking

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

   class SomeProductionProcess(CustomCachedSingleTon):

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

           pass
Run Code Online (Sandbox Code Playgroud)

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

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

Bre*_*bel 21

这是使用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
Run Code Online (Sandbox Code Playgroud)

如果你能,我建议使用pytest而不是unittest模块.它使您的测试代码更加清晰,并减少了您通过unittest.TestCase样式测试获得的大量样板.

  • `mock` 可以与任何一个一起使用。使用“pytest”或“unittest”之间的区别只是改变了测试函数的外观。我的示例使用“pytest”格式,您只需使用常规函数和内置的“assert”语句。查看@willnx [answer](http://stackoverflow.com/a/38579804/1547004),了解“unittest”测试的示例。 (2认同)

wil*_*lnx 7

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

import time

class SomeProductionProcess(CustomCachedSingleTon):

    def loaddata(self):
        time.sleep(30) # simulating a long running process
        return 2
Run Code Online (Sandbox Code Playgroud)

然后你模拟的单元测试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)
Run Code Online (Sandbox Code Playgroud)

或者它看起来像这样:

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)
Run Code Online (Sandbox Code Playgroud)

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


Mat*_*itt 5

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

from unittest.mock import Mock

mockObject = SomeProductionProcess
mockObject.loaddata = Mock(return_value=True)
Run Code Online (Sandbox Code Playgroud)

编辑:

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

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

SomeProductionProcess.loaddata = custom_method
Run Code Online (Sandbox Code Playgroud)