单元测试:修补 os 加入覆盖 os 加入测试文件

Unit test: patching os join overwrites os join in test file

我正在为使用 os.makedirsos.path.join 创建文件夹的函数编写单元测试。当我尝试模拟 class BuilddataHelpers 中使用的特定 os.path.join 时,它还会修补测试文件中的 os.path.join。如何在测试文件中仍然使用 os.path.join 的同时专门修补正在测试的文件中的 os.path.join

datamanager/builddatahelpers.py

import os
PATH = 'not/test/data/either'

class BuilddataHelpers:
    def create_folder(self, folder_name):
        create_folder_path = os.path.join(PATH, folder_name)
        os.makedirs(create_folder_path, exist_ok = True)
        return path

datamanager/datamanager.py

class DataManager(BuilddataHelpers):
     ...

test_builddatahelpers.py

import os

class TestBuilddataHelpers(unittest.TestCase):
    global TEST_PATH 
    TEST_PATH = 'tests/data'

    def setUp(self):
        super(TestBuilddataHelpers, self).setUp()
        self.dm = DataManager()
    
    @patch('datamanager.builddatahelpers.os.path.join', return_value=TEST_PATH)
    def test_create_folder_structure_on_ftp(self, mock_os_join):
        folder_name = 'test_folder'
        self.dm.create_folder(folder_name)
        self.assertTrue(os.path.exists(os.path.join(TEST_PATH, folder_name)))
        print('SUBFOLDER PATH: ' , os.path.join('not', 'test', 'data'))

输出SUBFOLDER PATH: tests/data。由于 os.makedirs 未修补,因此仍会创建该文件夹。

在您测试的代码中,您执行 import os,这意味着将使用 os.path.join 而不是本地引用。所以如果你这样做:

    @patch('datamanager.builddatahelpers.os.path.join', return_value=TEST_PATH)
    def test_create_folder_structure_on_ftp(self, mock_os_join):
        ...

这和写法完全一样:

    @patch('os.path.join', return_value=TEST_PATH)
    def test_create_folder_structure_on_ftp(self, mock_os_join):
        ...

如果您在测试代码中使用了 from x import y,那么第一个版本才有意义。在您的情况下,os.path.join 将为所有使用它的模块打补丁。 如果你想使用原来的os.path.join,你必须把它缓存在某个地方。 一种可能性是只使用:

from os.path import join

...
    @patch('os.path.join', return_value=TEST_PATH)
    def test_create_folder_structure_on_ftp(self, mock_os_join):
        folder_name = 'test_folder'
        self.dm.create_folder(folder_name)
        self.assertTrue(os.path.exists(join(TEST_PATH, folder_name)))
        print('SUBFOLDER PATH: ' , join('not', 'test', 'data'))

保存在 join 中的对 os.path.join 的本地引用将不会被修补。您还可以将其缓存为 class 变量:

import os

class TestBuilddataHelpers(unittest.TestCase):
    TEST_PATH = 'tests/data'
    join = os.path.join
...

    self.assertTrue(os.path.exists(self.join(TEST_PATH, folder_name)))

效果相同