如何全局模拟python中所有测试的方法
我的Django项目在许多应用程序的不同模块中进行了数百次测试。最近,我们添加了一个功能,在创建用户对象时(使用Django信号)发送电子邮件(通过sendgrid) 我们遇到的问题是,在运行测试时,许多用户要么显式创建,要么作为设备创建。这会导致在每个测试周期中发送数百封电子邮件,并且因为其中大多数邮件无效,我们会收到数百封回复。除了所涉及的成本,Sendgrid实际上由于这种奇怪的行为暂时中止了我们的账户 显然,我可以单独模拟每个测试的调用,但是这必须在数百个地方进行,并且我们必须记住在我们创建的所有未来测试中都要这样做如何全局模拟python中所有测试的方法,python,django,unit-testing,mocking,Python,Django,Unit Testing,Mocking,我的Django项目在许多应用程序的不同模块中进行了数百次测试。最近,我们添加了一个功能,在创建用户对象时(使用Django信号)发送电子邮件(通过sendgrid) 我们遇到的问题是,在运行测试时,许多用户要么显式创建,要么作为设备创建。这会导致在每个测试周期中发送数百封电子邮件,并且因为其中大多数邮件无效,我们会收到数百封回复。除了所涉及的成本,Sendgrid实际上由于这种奇怪的行为暂时中止了我们的账户 显然,我可以单独模拟每个测试的调用,但是这必须在数百个地方进行,并且我们必须记住在我们
是否有更简单的方法全局模拟所有测试的特定代码块(当然,在实际运行时保持原样)下面是两种实现模拟的方法 方法1:修改生产代码: 您可以创建一个伪包并将其导入以进行测试,而不是导入原始包。这种基于检查的导入可以在每个文件的开头进行 例如:
import os
if 'TEST' in os.environ:
import pseudoTime as time
else:
import time
print time.time
方法2:不修改生产代码:
在测试程序中,您可以导入实用程序包(包含问题中描述的电子邮件功能的包)并覆盖实用程序功能
例如:
import os
if 'TEST' in os.environ:
import pseudoTime as time
else:
import time
print time.time
考虑以下代码:
import time
def function():
return time.time()
测试代码可以执行以下操作:
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()
设置我在测试中全局(或至少部分测试中)需要的模拟/补丁
现在每次我需要它而不是导入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()
在你的测试中:
from myunittest import TestCase
class Test(TestCase):
... Your test
我在一个大型django项目中使用了两种方法 假设一个:
mymock=patch(“myapp.mymodule.MyClass.myu方法”)
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) 您可以在自定义基本测试类上添加模拟:
from mock import patch
from django.test import TestCase
class MyTestCase(TestCase):
def setUp(self):
super(MyTestCase, self).setUp()
my_mock.start()
def tearDown(self):
super(MyTestCase, self).tearDown()
my_mock.stop()
把它放在每个生产代码文件的开头?我讨厌它!说得对。编辑我的答案以提供其他方法。避免全局修补。看一看示例代码片段,它们是为了说明模拟测试的基本思想。