How to patch (mocking) tests with Errbot?


Keywords:python 


Question: 

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.


1 Answer: 

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