如何在单个 python 脚本中设置测试数据和测试用例

How do I set up the test data and the test cases in a single python script

我正在编写单元测试并尝试设置测试数据以用于同一 python 脚本中的测试用例。

但是,当我运行脚本时,它确实创建了测试数据,但是打印了一条数据不存在的错误消息,导致测试失败。只有当我再次运行脚本时,测试才能成功。

下面是我编写的简化脚本,用于弄清楚发生了什么。

import unittest
from ddt import ddt, file_data
import pandas

@ddt
class TestWhatever(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.setup_test_data()
        print("setUpClass is running")

    @classmethod
    def tearDownClass(cls):
        print("tearDownClass is running")

    @classmethod
    def setup_test_data(cls):
        data = pandas.DataFrame({'msg':["testing"]})
        data = data.transpose()
        with open("practice_test.json", "w") as file:
           file.write(data.to_json())
        print("setup_test_data is running")

    @file_data("practice_test.json")
    def test_whatever_possible(self, msg):
        print("test_whatever_possible is running :", msg)
        self.assertEqual('q', 'q')

    def test_whatever_impossible(self):
        print("test_whatever_impossible is running")
        self.assertEqual('n', 'n')

当我运行上面的脚本时,它打印:

setup_test_data is running
setUpClass is running
test_whatever_impossible is running
.EtearDownClass is running

======================================================================
ERROR: test_whatever_possible_00001_error (main.TestWhatever)
Error!
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\ddt.py", line 145, in wrapper
    return func(self, *args, **kwargs)
  File "C:\ddt.py", line 187, in func
    raise ValueError(message % file_attr)
ValueError: practice_test.json does not exist

----------------------------------------------------------------------
Ran 2 tests in 0.006s

FAILED (errors=1)

然后在第二个 运行 :

setup_test_data is running
setUpClass is running
test_whatever_impossible is running
.test_whatever_possible is running : testing
.tearDownClass is running

----------------------------------------------------------------------
Ran 2 tests in 0.005s

OK

此时我几乎迷路了...... 有人对此有线索吗?

所有Python代码都是可执行的。当加载 class 主体时,将执行其中的语句。装饰函数在 def 中创建带有咖啡的函数,将其分配给临时 class 命名空间中的名称(例如 test_whatever_possible),然后将其替换为调用装饰器。

这很重要的原因是装饰器是在 class 加载时调用的,而不是在测试 运行 时调用的。装饰器 file_data 检查文件是否存在(间接),因为它必须用文件中的值调用测试的函数替换测试函数。

您的第二个 运行 通过了,因为第一个 运行 已经创建了测试文件。我建议在 GitHub 上填写一个问题。 file_data 需要延迟打开文件,或者需要在某处清楚地记录意外行为。

您可以在 source code.file_data merely flags your test function for further processing. process_file_data 中确切地看到这种魔法发生的位置,然后检查该文件是否可用于扩展实际测试,或者创建一个只会引发您看到的错误的替换文件。

作为解决方法,您可以编写自己的装饰器来创建数据文件,例如

def create_data(name):
    def decorator(fn):
        def decorated(*args, **kwargs):
            data = pandas.DataFrame({"msg": ["testing"]})
            data = data.transpose()
            with open(name, "w") as file:
                file.write(data.to_json())
            res = fn(*args, **kwargs)
            os.unlink(name)
            return res
        return decorated
    return decorator

然后将其堆叠起来进行测试(并删除 setup_test_data 步骤):

@ddt
class TestWhatever(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        print("setUpClass is running")

    @classmethod
    def tearDownClass(cls):
        print("tearDownClass is running")

    @create_data("practice_test.json")
    @file_data("practice_test.json")
    def test_whatever_possible(self):
        print("test_whatever_possible is running :")
        self.assertEqual("q", "q")

更新:1 月 31 日

以下示例保留了将参数值传递给测试函数的 ddt 行为:

import json
import unittest
from ddt import ddt, FILE_ATTR


def create_file_data(value, data):
    def wrapper(func):
        with open(value, "w") as file:
            file.write(json.dumps(data))
        # this is what the file_data decorator does
        setattr(func, FILE_ATTR, value)
        return func

    return wrapper


@ddt
class TestWhatever(unittest.TestCase):
    @create_file_data("practice_test.json", {"msg": ["testing"]})
    def test_file_data(self, msg):
        print("test_file_data msg:", msg)


unittest.main()

当这是 运行 时,输出是:

test_file_data msg: ['testing']
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

使用上面的两个示例,您应该能够得出适合您的问题的解决方案。