我怎样才能使 SystemExit 的 assertRaise 结果为真?

How could I make it so that the assertRaise for SystemExit will result as true?

我正在尝试创建一个 python CLI 工具,用于在给定的时间间隔内监视特定进程。

我正在尝试自定义捕获 ValueError 时打印出来的消息,同时还尝试使用 sys.exit(1) 退出程序,可以在 [=15] 中找到=] example.py 内的函数。如果我不使用 sys.exit(1)main 函数中的 print 命令就会被执行。

整理好后,我开始执行单元测试(使用 unittest),通过使用 test_example.py,针对特定程序,检查当负值时是否引发 SystemExit传递给 time 参数。

因此,我怎样才能使 SystemExitassertRaise 结果为真?

我正在使用 python 3.10.4 和 argparse 1.1。

# example.py

import argparse, sys

def parse_args(args):
    parser = argparse.ArgumentParser() 
    parser.add_argument("-t", "--time", type=float, metavar=" ")
    return parser.parse_args(args)

def validate(data):
    try:
        if data.time < 0:            
            raise ValueError
    except ValueError:
        print(f"Time has a negative value: {data.time}. Please use a positive value")
        sys.exit(1)
    
def main():
    parsed_data = parse_args(sys.argv[1:])
    validate(parsed_data)    

    print(parsed_data.time)

if __name__ == '__main__':
    main()
# test_example.py

import unittest
from example import parse_args, validate

class TestExemplu(unittest.TestCase):    
    def test_negative_value(self):   
        with self.assertRaises(SystemExit) as cm:
            validate()

        the_exception = cm.exception
        self.assertEqual(the_exception.code, 1)


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

这是我得到的错误:

test_negative_value (test_example.TestExemplu) ... ERROR

======================================================================
ERROR: test_negative_value (test_example.TestExemplu)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Users\tester\Downloads\cli_mon_tool_1\test_example.py", line 16, in test_negative_value
    validate()
TypeError: validate() missing 1 required positional argument: 'data'

----------------------------------------------------------------------
Ran 1 test in 0.002s

FAILED (errors=1)

我想出了这个解决方案,根据这两个链接:

  1. Hide traceback unless a debug flag is set

  2. https://gist.github.com/maphew/e3a75c147cca98019cd8/7236687e4161b2c3c5eca0daec500a516cc21055


# example.py

import argparse, sys
debug = False

def parse_args(args):
    parser = argparse.ArgumentParser()
    parser.add_argument("-p", "--path", type=str, metavar=" ")
    parser.add_argument("-t", "--time", type=float, metavar=" ")
    return parser.parse_args(args)

def exceptionHandler(exception_type, exception, traceback, debug_hook=sys.excepthook):
    '''Print user friendly error messages normally, full traceback if DEBUG on.
       Adapted from 
    '''
    if debug:
        print('\n*** Error:')
        debug_hook(exception_type, exception, traceback)
    else:
        print("%s: %s" % (exception_type.__name__, exception))
sys.excepthook = exceptionHandler    

def validate(data):
    try:
        if data.time < 0:            
            raise ValueError
    except ValueError:        
        raise ValueError(f"Time has a negative value: {data.time}. Please use a positive value")
    try:
        if data.time == 0:            
            raise ValueError
    except ValueError as e:        
        raise ValueError(f"Time has a value of zero. Please use a positive value")    
    
def main():
    parsed_data = parse_args(sys.argv[1:])
    validate(parsed_data)

    print(parsed_data.path)
    print(parsed_data.time)

if __name__ == '__main__':
    main()

# test_example.py

import unittest
from example import parse_args, validate

class TestExemplu(unittest.TestCase):  
    
    def test_negative_value(self):
        parsed_data1 = parse_args(['-t', '-1'])       
        parsed_data2 = parse_args(['-t', '0'])       
        parsed_data3 = parse_args(['-t', '-1'])       
        self.assertRaises(ValueError, validate, parsed_data1)    
        self.assertRaises(ValueError, validate, parsed_data2)    
        try:    
            self.assertRaises(ValueError, validate, parsed_data2)
        except:
            pass     

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