假设我们有一个函数,可以使用终端程序 Convert 将图像转换为另一种格式。代码如下:
def convert_image(src, dest=None, extension='jpg', quality=100):
# Create default destination - same path just different extension
if dest is None:
dest = src.split('.')[0] + '.' + extension
try:
subprocess.check_call(['convert', src, '-quality', quality, dest])
except CalledProcessError:
raise ImageException('convert', 'Could not convert image')
return dest
现在我想测试这个函数以验证它是否按预期工作。
最直接的方法可能是只进行一个单元测试,提供真实图像的路径,并验证是否使用正确的扩展名创建了新图像。但问题是,很难知道创建的图像是否实际上是在质量设置为正确值的情况下创建的,并且在测试函数中实际转换真实图像有点尴尬。
如果我像这样调用该函数:
convert_image('/tmp/myimage.png')
我现在真正感兴趣的是,它从这个输入发送这个数组作为 check_call 的输入:
['convert', '/tmp/myimage.png', '-quality', 100, '/tmp/myimage.jpg']
如果确实如此,那么我就知道该函数在这种特殊情况下正在做正确的事情。
因此,如果用于测试目的的函数实际上只是在测试时返回此数组,并且仅在运行真实程序时转换图像,那就会很方便。
但是在所有函数中使用 if 语句来告诉函数为测试做不同的事情可能不太好,如果我实际上从未在测试函数中使用 check_call 那么我什至可能会出现语法错误我的测试代码未检测到该代码。
我正在寻找有关如何测试此代码或如何重构它以使其更易于测试的建议/讨论/技巧。我对使用 python 转换图像的更好方法不感兴趣,这个问题纯粹是关于代码可测试性。
那么,如果您能够测试此功能 - 您会怎么做?
最佳答案
我认为您很聪明地断言正确的数组已发送到check_call
,使其成为适当的单元测试(并且不同时测试转换应用程序)。为了能够做到这一点,您确实希望拦截对 check_call 的调用。
下面详细介绍了一种执行此操作的方法(请注意,代码未经测试,但应该给出该技术的概念)。为此,首先将对 check_call
的调用封装在一个单独的函数中,如下所示(convert_image
现在调用而不是 subprocess.check_call
) :
def check_call(args):
subprocess.check_call(args)
然后,在测试中,您可以将 check_call
替换为不同的函数,该函数断言将传递给 subprocess.check_call
的参数。下面显示了测试的示例:
import unittest
class ConvertImageTest(unittest.TestCase):
def test_convert_image(self):
# Test version of check_call to do the assertion
def assert_check_call(args):
expected = ['convert', '/tmp/myimage.png', '-quality', 100, '/tmp/myimage.jpg']
self.assertEquals(expected, args)
# Replace check_call with our test version
my.module.check_call = assert_check_call
# Perform the test
convert_image('/tmp/myimage.png')
使用这种方法也可以很简单地模拟抛出的异常并测试您对此的响应方式。
一个潜在的问题 - 之后您可能必须反向分配 my.module.check_call
- 说实话,不确定是否需要(我猜这取决于模块是否重新分配)在测试之间导入,希望这是真的)。
关于python - 您将如何测试这个功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17456514/