我正在研究的一个项目基本上都是使用django。在编写模型时,我发现有必要覆盖save()方法来分离要由worker工作的任务:
class MyModel(models.Model)
def _start_processing(self):
my_task.apply_async(args=['arg1', ..., 'argn'])
def save(self, *args, **kwargs):
"""Saves the model object to the database"""
# do some stuff
self._start_processing()
# do some more stuff
super(MyModel, self).save(*args, **kwargs)
在我的测试人员中,我想测试# do some stuff
和# do some more stuff
指定的保存覆盖部分,但不想运行任务。要做到这一点,我相信我应该使用模拟(我很新)。
在我的测试类中,我将其设置为跳过任务调用:
class MyModelTests(TestCase):
def setUp(self):
# Mock the _start_processing() method. Ha!
@patch('my_app.models.MyModel._start_processing')
def start_processing(self, mock_start_processing):
print('This is when the task would normally be run, but this is a test!')
# Create a model to test with
self.test_object = MyModelFactory()
由于工厂创建并保存了模型的实例,因此我需要在调用之前覆盖_start_processing()
方法。以上似乎不起作用(任务运行并失败)。我错过了什么?
答案 0 :(得分:1)
首先,你必须包装到装饰器而不是你想要用作替换的函数,但是"范围"你的模拟应该工作。因此,例如,如果您需要为整个_start_processing
类模拟MyModelTests
,则应将装饰器放在类定义之前。如果仅用于一种测试方法 - 仅用它包装测试方法。
其次,在类之外的某处定义start_processing
函数,并传递@patch('my_app.models.MyModel._start_processing', new=start_processing)
,这样它就会知道用什么作为实际方法的替代。但要注意匹配实际的方法签名,所以只需使用
def start_processing(self):
print('This is when the task would normally be run, but this is a test!')
第三,你必须为这个类中的每个测试用例添加mock_start_processing
参数(test _... methods),因为mocking的工作原理如下:)。
最后。您必须了解正在修补的target
。您当前的my_app.models.MyModel._start_processing
可能会被破坏。您必须使用其使用的路径来修补类,而不是使用DEFINED。因此,如果您要在MyModelFactory
内创建TestCase
的对象,并且MyModelFactory
位于my_app.factories
,并将MyModel
导入from .models import MyModel
,您将必须使用@patch('my_app.factories.MyModel._start_processing')
,而不是'my_app.models.MyModel._start_processing'
。
希望它有所帮助。