【问题标题】:How to unit test program interacting with block devices如何对与块设备交互的程序进行单元测试
【发布时间】:2016-10-06 05:15:54
【问题描述】:

我有一个程序可以与 linux 上的块设备(/dev/sda 等)进行交互和更改。我正在使用各种外部命令(主要是来自 fdisk 和 GNU fdisk 软件包的命令)来控制设备。我已经创建了一个类,作为块设备的大多数基本操作的接口(例如:它的大小是多少?它安装在哪里?等等)

这是一种查询分区大小的方法:

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 unit-testing


    【解决方案1】:

    您应该查看 mock 模块(我认为它现在是 Python 3 中 unittest 模块的一部分)。

    它使您无需依赖任何外部资源即可运行测试,同时让您能够控制模拟与代码的交互方式。

    我将从Voidspace 中的文档开始

    这是一个例子:

    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 返回您想要的任何输出,甚至在调用时引发 Exception。
    • 我想这可以工作,尽管 Popen 对象没有传递到方法中。我将如何插入 Popen 模拟?我不想让它成为一个参数,这会破坏方法的目的。
    • 在你的单元测试中,为 subprocess.Popen 应用一个补丁,然后为其设置一个返回值,以及它的通信方法和返回代码属性的返回值。我将添加一个简单的示例
    猜你喜欢
    • 2023-03-17
    • 2013-12-12
    • 2020-06-22
    • 2012-06-20
    • 1970-01-01
    • 1970-01-01
    • 2017-04-09
    • 2016-02-22
    • 1970-01-01
    相关资源
    最近更新 更多