Python 如何对与块设备交互的程序进行单元测试
我有一个程序,可以在linux上与块设备(/dev/sda等)进行交互和更改。我使用各种外部命令(主要是来自fdisk和GNU fdisk包的命令)来控制设备。我已经创建了一个类,作为块设备的大多数基本操作的接口(用于信息,如:它的大小?安装在哪里?等等) 下面是一种查询分区大小的方法:Python 如何对与块设备交互的程序进行单元测试,python,unit-testing,Python,Unit Testing,我有一个程序,可以在linux上与块设备(/dev/sda等)进行交互和更改。我使用各种外部命令(主要是来自fdisk和GNU fdisk包的命令)来控制设备。我已经创建了一个类,作为块设备的大多数基本操作的接口(用于信息,如:它的大小?安装在哪里?等等) 下面是一种查询分区大小的方法: def get_drive_size(device): """Returns the maximum size of the drive, in sectors. :device the de
def get_drive_size(device):
"""Returns the maximum size of the drive, in sectors.
:device the device identifier (/dev/sda and such)"""
query_proc = subprocess.Popen(["blockdev", "--getsz", device], stdout=subprocess.PIPE)
#blockdev returns the number of 512B blocks in a drive
output, error = query_proc.communicate()
exit_code = query_proc.returncode
if exit_code != 0:
raise Exception("Non-zero exit code", str(error, "utf-8")) #I have custom exceptions, this is slight pseudo-code
return int(output) #should always be valid
所以这个方法接受一个块设备路径,并返回一个整数。测试将以root用户身份运行,因为整个程序最终都必须以root用户身份运行
我是否应该尝试测试这些方法之类的代码?如果是,怎么做?我可以尝试为每个测试创建和挂载图像文件,但这似乎需要很大的开销,而且本身可能很容易出错。它需要块设备,因此我无法直接操作文件系统中的图像文件
正如一些答案所暗示的那样,我可以试着嘲笑,但这感觉不够。如果我模拟Popen对象,而不是输出,我似乎开始测试方法的实现。在这种情况下,这是正确的单元测试方法评估吗
我在这个项目中使用python3,我还没有选择单元测试框架。在没有其他原因的情况下,我可能只使用Python中包含的默认unittest框架。您应该研究模拟模块(我认为它现在是Python 3中unittest模块的一部分) 它使您能够在不依赖任何外部资源的情况下运行测试,同时控制模拟如何与代码交互 我将从中的文档开始 下面是一个例子:
import unittest2 as unittest
import mock
class GetDriveSizeTestSuite(unittest.TestCase):
@mock.patch('path/to/original/file.subprocess.Popen')
def test_a_scenario_with_mock_subprocess(self, mock_popen):
mock_popen.return_value.communicate.return_value = ('Expected_value', '')
mock_popen.return_value.returncode = '0'
self.assertEqual('expected_value', get_drive_size('some device'))
我在方法中使用了非python命令。如何模拟这些系统命令?您可以模拟subprocess.Popen,然后告诉它返回一个适合您希望测试的场景的值。mock的要点是,除了测试的代码之外,您不需要与其他任何东西进行交互。您可以让mock返回您想要的任何输出,甚至在调用时引发异常。我想这可以工作,尽管Popen对象没有传递到方法中。我将如何插入Popen mock?我不想让它成为一个参数,这会破坏方法的用途。在unittest中,对subprocess.Popen应用一个补丁,然后为它设置一个返回值,以及它的communicate方法和返回代码属性的返回值。我将添加一个简单的示例