我的Django项目在多个应用程序的各种模块中进行了数百次测试。最近我们添加了一个功能,在创建User对象(使用Django Signals)时发送电子邮件(通过sendgrid)。
我们遇到的问题是,在运行测试时,许多用户都是显式创建的,或者是作为fixtures创建的。这导致每个测试周期发送数百封电子邮件,并且因为大多数电子邮件无效,我们会获得数百次反弹。除了所涉及的费用之外,由于奇怪的行为,Sendgrid实际上暂时暂停了我们的帐户。
显然我可以单独模拟每个测试的调用,但这必须在数百个地方进行,我们必须记住在我们创建的所有未来测试中都这样做。
是否有一种更简单的方法可以全局模拟所有测试的特定代码块(当然实际运行时保持原样)
答案 0 :(得分:2)
我不使用Django,也许有一些惯用的方法可以在Django中做得很好。
我遇到此类问题的方法是创建自己的TestCase
课程,该课程从unittest.TestCase
延伸并覆盖setUpClass()
/ tearDownClass
/ setUp()
/ { {1}}在我的测试中(或者至少在其中的一部分中)设置全局需要的模拟/补丁。
现在每次我需要它而不是导入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()
答案 1 :(得分:1)
以下是两种实现模拟的方法。
方法1:修改生产代码:
您可以创建伪包并将其导入以进行测试,而不是导入原始包。这种基于检查的导入可以在每个文件的开头完成。
例如:
import os
if 'TEST' in os.environ:
import pseudoTime as time
else:
import time
print time.time
方法2:不修改生产代码:
在测试程序中,您可以导入实用程序包(包含问题中描述的电子邮件功能的程序包)并覆盖实用程序功能。
例如:
请考虑以下代码:
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
因此,测试代码可以导入实用程序文件,覆盖它提供的功能,然后对生产代码运行测试。
此方法优越,因为它不会更改生产代码。
答案 2 :(得分:0)
在大型Django项目中使用的两种方法
假设一个: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)您可以在自定义基础测试类上添加模拟:
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()