Search code examples
pythonerrbot

How to patch (mocking) tests with Errbot?


I'm trying to patch dependencies with my errbot tests. The problem I'm having is how errbot imports modules. It is not static and breaks my patch decorators as I add tests or they test in a different order.

I have plugin called EDB (edb.py). Inside of edb.py I import pyedb with import pyedb. This is located in my site-packages.

I have my test file test_edb.py and I try to patch my test methods like this

pytest_plugins = ["errbot.backends.test"]
extra_plugin_dir = '.'

from unittest.mock import patch  # noqa: E402

@patch('yapsy_loaded_plugin_EDB_1.pyedb', autospec=True)
def test_edb_testlist(pyedb_mock, testbot):
    testbot.push_message('!edb testlist')

    assert "Okay, let me get..." == testbot.pop_message()
    assert "I don't see any..." == testbot.pop_message()

Errbot adds this yapsy_loaded_plugin_EDB_<xx> path for module import but the xx depends on the order the test is run. This doesn't work, I need some static import path mypath.pyedb.

I'm hoping there is a different way to approach this. Maybe I can change the how I import the module so it's not dependent on errbot imports?

Here is a link to Errbot testing for reference.


Solution

  • My solution feels a bit hacky but it works. If anyone has a more elegant solution please share. I'll accept my own answer after awhile if there are no additional responses.

    So I've come across this before but I guess I still wasn't familiar enough with how patching works in Python with knowing where to patch. After reading the "Where to patch" documentation ( again :) ) I have a work-around given the dynamic imports with errbot.

    An errbot project folder will look something

    errbot-project/
    ├── data/
    │   ├── ...
    ├── plugins/
    │   ├── plugin1/
    |       ├── ...
    |   ├── plugin2/
    |       ├── ...
    

    I noticed that when errbot runs both the project directory ../errbot-project and all the plugin directories (e.g. ../errbot-project/plugins/plugin1) are added to sys.path.

    So I added a package to my project directory and I import that in my plugins. I then can patch my dependencies reliably from that package. Again read the Where to Patch documentation for full explanation why. It looks something like this.

    errbot-project/
    ├── data/
    │   ├── ...
    ├── plugins/
    │   ├── plugin1/
    |       ├── ...
    |   ├── plugin2/
    |       ├── ...
    ├── plugin_deps/
    |       ├── __init__.py
    

    Where my ../errbot-project/plugin_deps/__init__.py looks like

    ...
    import dep1
    import dep2
    ...
    

    And then in my plugin I use

    ...
    import plugin_deps as pdep
    ...
    def method():
        pdep.dep1.method()
    ...
    # note, you cannot use 
    # from plugin_deps import dep1
    # this changes 'where' python looks up the module and
    # and 'breaks' your patch 
    

    And finally my test code looks like

    @patch('plugin_deps.dep1', autospec=True) 
    def test_get_tl_tabulation(my_mock, testbot):
        # test code here