You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用unittest.mock捕获subprocess.call真实退出码(兼容Python2.7+)

Testing subprocess.call Exit Codes with unittest.mock (Python 2.7+)

Great question! Since you can't modify the run_hook function and need Python 2.7 compatibility, the key is to use unittest.mock (or the standalone mock library for Python 2.7) to wrap the real subprocess.call function—this lets you capture actual exit codes while letting run_hook behave as normal.

Here's a step-by-step solution:

First, let's assume your external somemodule.py looks like this (for context):

# somemodule.py
import subprocess

def run_hook(command):
    # You can't modify this function
    exit_code = subprocess.call(command, shell=True)
    if exit_code == 0:
        print("Hook succeeded")
    else:
        print("Hook failed with code {}".format(exit_code))
    return exit_code

Test Code Implementation

For Python 2.7, install the mock library first with pip install mock. For Python 3, unittest.mock is included in the standard library.

import unittest
# For Python 2.7: from mock import patch
# For Python 3: from unittest.mock import patch
from mock import patch
import subprocess
import somemodule

class TestRunHook(unittest.TestCase):
    def setUp(self):
        # Store captured exit codes across test runs
        self.captured_exit_codes = []
        
        # Create a wrapper function that calls real subprocess.call and captures exit codes
        def capture_real_exit_code(*args, **kwargs):
            real_exit_code = subprocess.call(*args, **kwargs)
            self.captured_exit_codes.append(real_exit_code)
            return real_exit_code
        
        # Patch the subprocess.call instance that run_hook uses
        self.patch = patch('somemodule.subprocess.call', side_effect=capture_real_exit_code)
        self.patch.start()
    
    def tearDown(self):
        # Clean up the patch after each test
        self.patch.stop()
    
    def test_run_hook_success(self):
        # Run a cross-platform command that exits with code 0
        result = somemodule.run_hook('python -c "exit(0)"')
        
        # Assert the real exit code was captured
        self.assertEqual(self.captured_exit_codes[-1], 0)
        # Assert run_hook returns the correct code
        self.assertEqual(result, 0)
    
    def test_run_hook_failure(self):
        # Run a cross-platform command that exits with code 1
        result = somemodule.run_hook('python -c "exit(1)"')
        
        self.assertEqual(self.captured_exit_codes[-1], 1)
        self.assertEqual(result, 1)

if __name__ == '__main__':
    unittest.main()

Key Details:

  1. Patch the Right Instance: We patch somemodule.subprocess.call instead of subprocess.call directly. This is critical because run_hook imports subprocess into its own namespace—we need to mock the version it actually uses.
  2. Capture Real Exit Codes: The capture_real_exit_code wrapper invokes the real subprocess.call, stores the exit code, and returns it. This ensures run_hook behaves exactly as it would in production, while letting you inspect the exit code for assertions.
  3. Cross-Platform Commands: Using python -c "exit(n)" works on both Windows and Unix-like systems, so your tests are portable.
  4. Cleanup: The setUp and tearDown methods ensure the patch is applied only for the duration of each test, preventing side effects between test cases.

Alternative: Mocking Exit Codes (No Real Commands)

If you don't want to execute real system commands (for speed or safety), you can mock subprocess.call to return specific exit codes and test how run_hook handles them:

def test_run_hook_handles_failure_mocked(self):
    with patch('somemodule.subprocess.call', return_value=2):
        result = somemodule.run_hook('any_command')
        self.assertEqual(result, 2)
        # Add assertions for how run_hook responds to failure (e.g., logs, error handling)

This approach gives you full control over the exit codes without running real processes, which is useful for edge cases.

内容的提问来源于stack exchange,提问作者Andre Pastore

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:35:30