运行时错误:使用 pytest 运行 Frappe 单元测试时未绑定对象

问题描述 投票:0回答:1

我正在尝试在不使用 FrappeTestCase 类的情况下为 Frappe Doctype 实现单元测试。我的实现在使用 bench run-tests 命令运行测试时工作正常,但在使用 pytest 时失败。这是我的 Doctype 和单元测试实现。

注释

  1. 我想使用
    pytest
    运行测试,而不是使用
    bench
    命令。
  2. 使用
    bench run-tests
    命令有效,但使用
    pytest
    无效。
  3. 使用
    python -m unittest
    运行测试也会给出相同的错误。

文档类型实现:

class FeedbackClassification(Document):
    def validate(self):
        self.validate_classification_code()

    def validate_classification_code(self):
        if frappe.db.exists(
            "Feedback Classification", {"classification_code": self.classification_code, "name": ("!=", self.name)}
        ):
            frappe.throw(
                _("Duplicate classification codes {0} already exists").format(frappe.bold(self.classification_code)),
                title=_("Duplicate Classification Code"),
                exc=frappe.UniqueValidationError,
            )

单元测试实施:

class TestFeedbackClassification(unittest.TestCase):
    def setUp(self):
        with patch.object(FeedbackClassification, "__init__", lambda x: None):
            self.mock_feedback_classification = FeedbackClassification()

        patcher = patch(
            "frappe.throw", side_effect=lambda *args, **kwargs: (_ for _ in ()).throw(UniqueValidationError(args[0]))
        )
        self.mock_throw = patcher.start()
        self.addCleanup(patcher.stop)

        self.mock_feedback_classification.classification_code = None
        self.mock_feedback_classification.name = "Test Classification"

    def set_classification_code(self, classification_code):
        self.mock_feedback_classification.classification_code = classification_code

    @patch("frappe.db.exists")
    def test_validate_duplicate_classification_code(self, mock_exists):
        self.set_classification_code("Classification 1")
        mock_exists.return_value = True

        with self.assertRaises(UniqueValidationError) as cm:
            self.mock_feedback_classification.validate()

        expected_message = "Duplicate classification codes <strong>Classification 1</strong> already exists"
        self.assertIn(expected_message, str(cm.exception))

    @patch("frappe.db.exists")
    def test_validate_no_duplicate_classification_code(self, mock_exists):
        self.set_classification_code("Classification")
        mock_exists.return_value = False

        try:
            self.mock_feedback_classification.validate()
        except UniqueValidationError:
            self.fail("validate() raised UniqueValidationError unexpectedly!")

使用pytest运行测试时,出现以下错误:

doctype/feedback_classification/test_feedback_classification.py::TestFeedbackClassification::test_validate_duplicate_classification_code failed: /usr/local/lib/python3.11/unittest/mock.py:1372: in patched
    with self.decoration_helper(patched,
/usr/local/lib/python3.11/contextlib.py:137: in __enter__
    return next(self.gen)
/usr/local/lib/python3.11/unittest/mock.py:1354: in decoration_helper
    arg = exit_stack.enter_context(patching)
/usr/local/lib/python3.11/contextlib.py:505: in enter_context
    result = _enter(cm)
/usr/local/lib/python3.11/unittest/mock.py:1443: in __enter__
    original, local = self.get_original()
/usr/local/lib/python3.11/unittest/mock.py:1406: in get_original
    original = target.__dict__[name]
frappe-bench/env/lib/python3.11/site-packages/werkzeug/local.py:311: in __get__
    obj = instance._get_current_object()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    def _get_current_object() -> T:
        try:
            return get_name(local)  # type: ignore[return-value]
        except AttributeError:
>           raise RuntimeError(unbound_message) from None
E           RuntimeError: object is not bound

frappe-bench/env/lib/python3.11/site-packages/werkzeug/local.py:490: RuntimeError

我尝试过的:

  • 使用基准运行测试运行测试没有任何问题。
  • 确保正确应用补丁。

预期行为:

  • 测试应该使用 pytest 成功运行,就像使用基准运行测试一样。

环境:

  • 冰沙版本:14.78.2
  • Python版本:3.11
  • pytest版本:8.3.2
python unit-testing pytest frappe
1个回答
0
投票

Frappe 框架初始化应用程序上下文的方式与

bench run-tests
运行测试的方式不同。直接使用
pytest
运行测试时,可能未设置必要的 Frappe 应用程序上下文,这可能会导致错误,尤其是对于依赖此上下文的 Frappe 会话和其他本地对象。

要解决此问题,请尝试在测试设置中手动初始化 Frappe 应用程序上下文。您可以在执行测试之前使用上下文管理器建立 Frappe 环境。 这是一个可以用来解决此问题的代码模板:

进口冰沙 从冰沙进口_ 从 frappe.exceptions 导入 UniqueValidationError 导入单元测试 从unittest.mock导入补丁

类 TestFeedbackClassification(unittest.TestCase):

@classmethod
def setUpClass(cls):
    # Initialize the Frappe framework
    frappe.init(site='your_site.local')  # Replace with your actual site.
    frappe.connect()

def setUp(self):
    with patch.object(FeedbackClassification, "__init__", lambda x: None):
        self.mock_feedback_classification = FeedbackClassification()
        patcher = patch("frappe.throw", side_effect=lambda *args, **kwargs: (_ for _ in ()).throw(UniqueValidationError(args[0])))
        self.mock_throw = patcher.start()
        self.addCleanup(patcher.stop)
        self.mock_feedback_classification.classification_code = None
        self.mock_feedback_classification.name = "Test Classification"

def tearDown(self):
    pass

@classmethod
def tearDownClass(cls):
    frappe.destroy()
  • 确保您正在修补正确的方法和属性,因为如果修补程序未准确定位依赖于 Frappe 上下文的必要调用,则可能会发生错误。
  • 如果初始化上下文仍然导致问题,请考虑使用
    pytest
    固定装置来封装测试的设置和拆卸逻辑。
© www.soinside.com 2019 - 2024. All rights reserved.