这个Python模拟补丁有什么问题?

Ste*_*art 5 python django unit-testing mocking

我在单元测试中嘲笑导入的模块时遇到了麻烦.我正在尝试tracker.models使用mock模块在我的模块中模拟PIL Image类.我知道你应该模仿使用它们的东西,所以我写作@mock.patch('tracker.models.Image')我的装置进行单元测试.我正在尝试检查下载的图像是否作为PIL图像打开.模拟补丁似乎覆盖了整个Image模块.这是我运行测试时遇到的错误:

File "/home/ubuntu/workspace/tracker/models.py", line 40, in set_photo
    width, height = image.size
ValueError: need more than 0 values to unpack
Run Code Online (Sandbox Code Playgroud)

这是我的单元测试:

test_models.py

@responses.activate
@mock.patch('tracker.models.Image')
def test_set_photo(self, mock_pil_image):
    # Initialize data
    hammer = Product.objects.get(name="Hammer")
    fake_url = 'http://www.example.com/prod.jpeg'
    fake_destination = 'Hammer.jpeg'

    # Mock successful image download using sample image. (This works fine)
    with open('tracker/tests/test_data/small_pic.jpeg', 'r') as pic:
        sample_pic_content = pic.read()
    responses.add(responses.GET, fake_url, body=sample_pic_content, status=200, content_type='image/jpeg')

    # Run the actual method
    hammer.set_photo(fake_url, fake_destination)

    # Check that it was opened as a PIL Image
    self.assertTrue(mock_pil_image.open.called,
                    "Failed to open the downloaded file as a PIL image.")
Run Code Online (Sandbox Code Playgroud)

这是它正在测试的一段代码.

跟踪器/ models.py

class Product(models.Model):
    def set_photo(self, url, filename):
        image_request_result = requests.get(url)
        image_request_result.content
        image = Image.open(StringIO(image_request_result.content))

        # Shrink photo if needed
        width, height = image.size  # Unit test fails here
        max_size = [MAX_IMAGE_SIZE, MAX_IMAGE_SIZE]
        if width > MAX_IMAGE_SIZE or height > MAX_IMAGE_SIZE:
            image.thumbnail(max_size)
        image_io = StringIO()
        image.save(image_io, format='JPEG')
        self.photo.save(filename, ContentFile(image_io.getvalue()))
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 6

您需要配置Image.open包含size属性的返回值:

opened_image = mock_pil_image.open.return_value
opened_image.size = (42, 83)
Run Code Online (Sandbox Code Playgroud)

现在,当您的测试函数调用Image.open返回的MagicMock实例时,将具有size一个元组属性.

对于需要返回某些内容的任何其他方法或属性,您可以执行相同的操作.

opened_image然后,该参考也可用于测试被测功能的其他方面; 你现在可以断言,image.thumbnailimage.save被称为:

opened_image = mock_pil_image.open.return_value
opened_image.size = (42, 83)

# Run the actual method
hammer.set_photo(fake_url, fake_destination)

# Check that it was opened as a PIL Image
self.assertTrue(mock_pil_image.open.called,
                "Failed to open the downloaded file as a PIL image.")

self.assertTrue(opened_image.thumbnail.called)
self.assertTrue(opened_image.save.called)
Run Code Online (Sandbox Code Playgroud)

这使您可以非常准确地测试缩略图大小逻辑是否正常工作,例如,无需测试PIL是否正在执行其操作; 毕竟,PIL没有在这里进行测试.