Seite 1 von 1
Bedingter Import für Unit-Tests
Verfasst: Donnerstag 18. Oktober 2018, 22:37
von ThomasT
Hallo,
ich habe ein Python Modul aaa mit (vereinfacht) einer Klasse AAA und einer globalen Variable.
In der Klasse wird ein anderes Modul benutzt. Z.B. pymqi, das oben importiert wird.
Will ich diese Klasse unit testen, dann schreibe ich eine Datei mit dem Unit-Test und importiere das Modul aaa.
Wie kann ich erreichen, dass für den Test pymqi nicht importiert wird? Denn es wird sonst knallen, wenn die shared libs fehlen.
Wie kann ich im Modul aaa die globale Variable (z.B. eine Konfiguration) setzen?
Was sind "best practices"?
Gruß Thomas
Re: Bedingter Import für Unit-Tests
Verfasst: Donnerstag 18. Oktober 2018, 23:02
von __deets__
Das Stichwort dafür heißt dependency injection. Du kannst auf verschiedene Arten vorgehen:
- dein Modul aaa importiert pymqi NICHT. Sondern bekommt das Modul als Argument. Dadurch kannst du das mocken.
- du mocks das Modul durch ein pymqi-Mock-Modul das im sys.path vor dem original liegt, und dadurch zuerst (und alleinig) importiert wird.
Re: Bedingter Import für Unit-Tests
Verfasst: Freitag 19. Oktober 2018, 00:00
von ThomasT
Wie meinst du die erste Variante?
Grüße Thomas
Re: Bedingter Import für Unit-Tests
Verfasst: Freitag 19. Oktober 2018, 09:17
von Sirius3
Also, die zweite Methode ist das, was man normalerweise macht, ob jetzt über sys.path oder sys.modules, ist zweitrangig. Dafür gibt es normalerweise schon fertige Funktionen:
https://docs.pytest.org/en/latest/monkeypatch.html
Globale Variablen sollte es in Modulen nicht geben. Für "Konstanten" die in komplexeren Funktionsaufrufen generiert werden, kann man genauso monkey-patching benutzen, in dem man die Funktion überschreibt:
Code: Alles auswählen
import database
configuration = database.get_config_from_database()
im Test:
Code: Alles auswählen
import database
def test_get_config():
return {'abc': 5}
database.get_config_from_database = test_get_config
import module_to_test
Hier muß man natürlich aufpassen, dass das Monkey-Patching schon vorher stattfindet, oder eben gleich das ganze Module `database` durch ein mockup erstetzen:
Code: Alles auswählen
import sys
import mock_database
sys.modules['database'] = mock_database
Re: Bedingter Import für Unit-Tests
Verfasst: Freitag 19. Oktober 2018, 11:48
von ThomasT
Hi,
in thomastest.py
Code: Alles auswählen
#!/usr/bin/python
import sys
import unittest
import ttmock
sys.modules['springpython.jms.core'] = ttmock
import thomas
In thomas.py
Code: Alles auswählen
#!/usr/bin/python
from springpython.jms.core import JmsTemplate
from springpython.jms.factory import WebSphereMQConnectionFactory
Und wenn ich thomastest.py start bekomme ich diese Exception:
Code: Alles auswählen
Traceback (most recent call last):
File "thomastest.py", line 9, in <module>
import thomas
File "/cygdrive/e/Projekte/python/thomas.py", line 38, in <module>
from springpython.jms.core import JmsTemplate
ImportError: No module named springpython.jms.core
Re: Bedingter Import für Unit-Tests
Verfasst: Freitag 19. Oktober 2018, 11:57
von __deets__
Wo geht das nicht. In sys.modulues sind nur toplevel Module. Du musst also ein springpython-Modul mocken, das wiederum die anderen untermodule/Pakete kennt.
Re: Bedingter Import für Unit-Tests
Verfasst: Freitag 19. Oktober 2018, 13:06
von ThomasT
Ich dachte das sei einfach ein String-Lookup in erster Linie.
Anscheinend weiss ich nicht genug darüber, wie Modulimports funktionieren.