I went on a more traditional way by adding a tests directory and multiple __init__.py
files :
> files/
> - a.txt
> - b.txt
> library/
> - __init__.py
> - common_code.py
> module_utils/
> - __init__.py
> - custom_module1.py
> - custom_module2.py
> templates/
> - c.txt.j2
> - d.txt.j2
> tests/
> - __init__.py
> - test_custom_module1.py
> - test_custom_module2.py
> - test_common_code.py
> playbook.yml
and imported the other files to test in the units tests like this :
from module_utils.custom_module1 import *
from module_utils.custom_module2 import *
from library.common_code import *
I had to modify the import in the custom modules :
try:
from ansible.module_utils.common_code import util
except ImportError: # We except an ImportError in unit tests so we import it differently :D
from module_utils.common_code import util
And added some specific Exception to handle the exit_json and fail_json as stated here like this :
self.module = MagicMock()
self.module.exit_json.side_effect = AnsibleExitJson(Exception)
self.module.fail_json.side_effect = AnsibleFailJson(Exception)
and later in a unit test function
self.module.fail_json.assert_called()
self.module.exit_json.assert_not_called()