简体   繁体   English

如何修补/模拟导入?

[英]How to patch/mock import?

I'm writing tests for airflow dag and running into issue mocking/patching the dag.我正在为 airflow dag 编写测试并遇到模拟/修补 dag 的问题。

# dag.py
from airflow.models import Variable

ENVIRONMENT = Variable.get("environment")
# test_dag.py
import dag

class TestDAG(TestCase):
    def test_something(self):
        pass

Because I'm just setting variable outside of function or class, it runs Variable.get() during import.因为我只是在 function 或 class 之外设置变量,所以它在导入期间运行 Variable.get()。 This will be give me a SQLAlchemy error cause it's trying to connect to a db and fetch variable.这将给我一个 SQLAlchemy 错误,因为它正在尝试连接到数据库并获取变量。

sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: variable
[SQL: SELECT variable.val AS variable_val, variable.id AS variable_id, variable."key" AS variable_key, variable.is_encrypted AS variable_is_encrypted 
FROM variable 
WHERE variable."key" = ?
 LIMIT ? OFFSET ?]
[parameters: ('environment', 1, 0)]

Is there a way to patch/mock airflow.models.Variable before it's imported?有没有办法在导入之前修补/模拟 airflow.models.Variable?

You'll need to defer importing the file until you can set a Variable value into the test database.您需要推迟导入文件,直到您可以将Variable值设置到测试数据库中。 A startTestRun method would be the perfect place. startTestRun方法将是一个完美的地方。

I have some workarounds but not a definite answer:我有一些解决方法,但没有明确的答案:

  1. You can move this line ENVIRONMENT = Variable.get("environment") into inside a function, instead of global.您可以将此行ENVIRONMENT = Variable.get("environment")移动到 function 内部,而不是全局。 This way, it will not be executed when imported and you can add this mock to conftest.py :这样,它不会在导入时执行,您可以将此模拟添加到conftest.py
@pytest.fixture(autouse=True)
def mock_airflow_variables(mocker):
        mocker.patch.object(target=Variable, attribute="get", return_value="test")
  1. You can import the module inside the test function. This way, the mock will be set before calling import.您可以在测试 function 中导入模块。这样,将在调用导入之前设置模拟。

You can mock the import before importing the file您可以在导入文件之前模拟导入

import unittest
from unittest.mock import MagicMock

import sys


class TestDAG(unittest.TestCase):

    def test_something(self):
        sys.modules['airflow.models'] = MagicMock()
    
        # This returns the MagicMock instance
        from airflow.models import Variable 

        # Set the return_value of the .get() call
        Variable.get.return_value = "TEST" 

        # import the dag after
        import dag

        Variable.get.assert_called_once()
        assert dag.ENVIRONMENT == "TEST"


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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM