如何捕获我动态调用的函数中抛出的异常?

时间:2018-02-02 03:23:15

标签: python-3.x

我分心了,最后在python中编写了一个测试框架。我正在努力解决这个问题。

在我的断言期间,我想抛出异常作为将问题冒泡到run_test()方法的一种方式,而不要求用户对框架有任何了解。问题在于,当我这样做时,似乎没有兑现try / catch块。

这是我初出茅庐的框架的缩减版本:

# test_framework.py
import inspect
import module_containing_tests

class AssertionException(Exception):
    def __init__(self, message):
        self.message = message
    def __str__(self):
        return self.message

def run_test(test_name, test_method):
    try:
        print(">", test_name)
        test_method()
        print("Passed")
    except AssertionException as error:
        print("Failed")
        print(str(error))

def assert_true(conditional):
    if not conditional:
        raise AssertionException("Expected True. Was False")

def test(func):
    func.is_test = True
    return func

members = inspect.getmembers(module_containing_tests)
for member in members:
    if "is_test" in dir(member[1]) and not member[0] == "module_containing_tests":
        run_test(member[0], member[1])

包含测试的模块如下所示:

# module_containing_tests.py
from test_framework import *

@test
def passing_test():
    assert_true(1 + 2 == 3)

@test
def failing_test():
    assert_true(1 + 2 == 5)

输出中包含所有异常堆栈跟踪,并且还会暂停执行

λ python test_framework.py
> failing_test
Traceback (most recent call last):
  File "test_framework.py", line 29, in <module>
    run_test(member[0], member[1])
  File "test_framework.py", line 13, in run_test
    test_method()
  File "C:\Git\simpy-test\module_containing_tests.py", line 9, in failing_test
    assert_true(1 + 2 == 5)
  File "C:\Git\simpy-test\test_framework.py", line 20, in assert_true
    raise AssertionException("Expected True. Was False")
test_framework.AssertionException: Expected True. Was False

我想要的是这样的:

λ python test_framework.py
> failing_test
Expected True. Was False
Failed
> passing_test
Passed

2 个答案:

答案 0 :(得分:3)

我认为问题部分在于两个文件之间的循环引用可能会破坏方法的可见性(以某种方式解释here),部分可能在方法中。如果您考虑有多少其他测试框架可以工作,您通常会有3个元素,要测试的单元,测试框架和测试运行器。

因此,如果我们试图将所有逻辑分开,那么你最终会得到:

<强> test_framework.py

# test_framework.py
class AssertionException(Exception):
    pass


def test(f):
   f.is_test = True
   return f


def assert_true(conditional):
    if not conditional:
        raise AssertionException("Expected True. Was False")

<强> test_runner.py

# test_runner.py
import inspect

import unit_test
from test_framework import AssertionException


def run_test(test_name, test_method):
    try:
        print(">", test_name)
        test_method()
        print("Passed")
    except AssertionException as error:
        print("Failed with AssertionException: " + str(error))
    except Exception as error:
        print("Failed with Exception: " + str(error))


if __name__ == "__main__":
    members = inspect.getmembers(unit_test)
    for member in members:
        if "is_test" in dir(member[1]):
            run_test(member[0], member[1])

<强> unit_test.py

# unit_test.py
from test_framework import *


@test
def a_passing_test():
    assert_true(1 + 2 == 3)


@test
def z_failing_test():
    assert_true(1 + 2 == 5)

通过此设置,将删除循环依赖关系,并且会遵循所有可见性上下文,并且输出/行为是预期的。

我希望它有所帮助。

答案 1 :(得分:1)

不确定这是你想要的但是这样有用 从这里复制Hide traceback unless a debug flag is set

输出:

$ ./test_framework.py
> a_passing_test
Passed
> z_failing_test
test_framework.AssertionException: Expected True. Was False

第一档:

#!/usr/bin/env python3
#test_framework.py

import inspect 
import module_containing_tests 
import sys


class AssertionException(Exception):
    def __init__(self, message):
        self.message = message
    def __str__(self):
        return self.message

def run_test(test_name, test_method):
    try:
        print(">", test_name)
        test_method()
        print("Passed")
    except AssertionException as error:
        print("Failed")
        print(str(error))

def assert_true(conditional):
    if not conditional:
        raise AssertionException("Expected True. Was False")

def test(func):
    func.is_test = True
    return func


sys.tracebacklimit=0
members = inspect.getmembers(module_containing_tests)
for member in members:
    if "is_test" in dir(member[1]) and not member[0] == "module_containing_tests":
        run_test(member[0], member[1])

第二档:

#!/usr/bin/env python3
#module_containing_tests.py
from test_framework import *

@test
def a_passing_test():
    assert_true(1 + 2 == 3)

@test
def z_failing_test():
    assert_true(1 + 2 == 5)