如何为python中的所有测试全局模拟一个方法

2024-05-16 21:21:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我的Django项目在多个应用程序的不同模块中有数百个测试。最近我们添加了一个特性,在创建用户对象(使用Django信号)时(通过sendgrid)发送电子邮件。在

我们遇到的问题是,在运行测试时,许多用户要么显式创建,要么作为fixture创建。这会导致在每个测试周期中发送数百封电子邮件,由于大多数电子邮件无效,我们会收到数百封退回邮件。除了所涉及的成本外,Sendgrid实际上还因为这种奇怪的行为暂时暂停了我们的账户。在

显然,我可以单独模拟每个测试上的调用,但是这必须在数百个地方进行,并且我们必须记住在我们创建的所有未来测试中都要这样做。在

有没有一种更简单的方法来全局模拟所有测试的特定代码块(当然,在实际运行时保持原样)


Tags: 模块项目对象django用户应用程序信号电子邮件
3条回答

下面是两种实现模拟的方法。在

方法1:修改生产代码:

您可以创建一个伪包并导入它以进行测试,而不是导入原始包。这种基于检查的导入可以在每个文件的开头完成。在

例如:

import os
    if 'TEST' in os.environ:
        import pseudoTime as time
    else:
        import time

print time.time

方法2:不修改生产代码:

在测试程序中,可以导入实用程序包(包含问题中描述的电子邮件功能的包)并覆盖实用程序函数。在

例如:

考虑以下代码:

^{2}$

测试代码可以执行以下操作:

import code
import time

def helloWorld():
    return "Hello World"

print "Before changing ...", code.function()
oldTime = time.time # save
time.time = helloWorld
print "After changing ...", code.function()
time.time = oldTime # revert back

上述试验的输出为:

Before changing ... 1456487043.76
After changing ... Hello World

因此,测试代码可以导入实用程序文件,覆盖它提供的函数,然后在生产代码上运行测试。在

这种方法是优越的,因为它不改变生产代码。在

我不使用Django,也许有一些惯用的方法可以在Django中做好它。在

我解决这类问题的方法是创建我自己的TestCase类,从unittest.TestCase扩展并重写setUpClass()/tearDownClass/setUp()/tearDown(),以设置我在测试中全局需要的模拟/补丁(或至少在其中的一部分)。在

现在每当我需要它而不是导入unittest.TestCase模块时,我都要导入myunittest.TestCase

示例:myunittest.py

import unittest

class TestCase(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        super(TestCase, cls).setUpClass()
        # Init your class Mock/Patch

    @classmethod
    def tearDownClass(cls):
        # Remove Mocks or clean your singletons
        super(TestCase, cls).tearDownClass()

    def setUp(self):
        super(TestCase, self).setUp()
        # Init your obj Mock/Patch

    @classmethod
    def tearDown(self):
        # ... if you need it
        super(TestCase, self).tearDown()

在你的测试中:

^{2}$

我在一个大型django项目中使用的两种方法

假设a:my_mock = patch("myapp.mymodule.MyClass.my_method")

1)可以在自定义测试运行程序类中添加模拟:

from mock import patch
from django.test.runner import DiscoverRunner

class MyTestRunner(DiscoverRunner):
    @my_mock
    def run_tests(self, test_labels, **kwargs):
         return super(MyTestRunner, self).run_tests(test_labels, **kwargs)

2)可以在自定义基测试类上添加模拟:

^{2}$

相关问题 更多 >