Védje meg kódját egységtesztekkel

Fontos

This tutorial is an extension of the Server framework 101 tutorial. Make sure you have completed it and use the estate module you have built as a base for the exercises in this tutorial.

Hivatkozás: Odoo tesztkeretrendszer: Tanulja meg a legjobb gyakorlatokat (Odoo Experience 2020) a YouTube-on.

A tesztek írása több okból is szükséges. Íme egy nem kimerítő lista:

  • Biztosítsa, hogy a kód a jövőben ne sérüljön

  • Határozza meg a kód hatókörét

  • Használati esetek példáinak bemutatása

  • Ez egy módja a kód technikai dokumentálásának

  • Segítse a kódolást azzal, hogy meghatározza célját, mielőtt elkezdene dolgozni rajta

Tesztfuttatás

Mielőtt megtanulnánk, hogyan írjunk teszteket, meg kell tanulnunk, hogyan futtassuk őket.

$ odoo-bin -h
Usage: odoo-bin [options]

Options:
--version             show program's version number and exit
-h, --help            show this help message and exit

[...]

Testing Configuration:
  --test-file=TEST_FILE
                      Launch a python test file.
  --test-enable       Enable unit tests.
  --test-tags=TEST_TAGS
                      Comma-separated list of specs to filter which tests to
                      execute. Enable unit tests if set. A filter spec has
                      the format: [-][tag][/module][:class][.method] The '-'
                      specifies if we want to include or exclude tests
                      matching this spec. The tag will match tags added on a
                      class with a @tagged decorator (all Test classes have
                      'standard' and 'at_install' tags until explicitly
                      removed, see the decorator documentation). '*' will
                      match all tags. If tag is omitted on include mode, its
                      value is 'standard'. If tag is omitted on exclude
                      mode, its value is '*'. The module, class, and method
                      will respectively match the module name, test class
                      name and test method name. Example: --test-tags
                      :TestClass.test_func,/test_module,external  Filtering
                      and executing the tests happens twice: right after
                      each module installation/update and at the end of the
                      modules loading. At each stage tests are filtered by
                      --test-tags specs and additionally by dynamic specs
                      'at_install' and 'post_install' correspondingly.
  --screencasts=DIR   Screencasts will go in DIR/{db_name}/screencasts.
  --screenshots=DIR   Screenshots will go in DIR/{db_name}/screenshots.
                      Defaults to /tmp/odoo_tests.

$ # run all the tests of account, and modules installed by account
$ # the dependencies already installed are not tested
$ # this takes some time because you need to install the modules, but at_install
$ # and post_install are respected
$ odoo-bin -i account --test-enable
$ # run all the tests in this file
$ odoo-bin --test-file=addons/account/tests/test_account_move_entry.py
$ # test tags can help you filter quite easily
$ odoo-bin --test-tags=/account:TestAccountMove.test_custom_currency_on_account_1

Integrációs Botok

Megjegyzés

Ez a szakasz kizárólag az Odoo alkalmazottai és azok számára készült, akik hozzájárulnak a github.com/odoo-hoz. Egyébként erősen ajánljuk, hogy legyen saját CI-je.

Amikor egy tesztet írunk, fontos biztosítani, hogy mindig sikeresen fusson, amikor módosításokat alkalmazunk a forráskódon. Ennek a feladatnak az automatizálására egy fejlesztési gyakorlatot használunk, amelyet Folyamatos Integrációnak (CI) nevezünk. Ezért van néhány botunk, amelyek különböző időpontokban futtatják az összes tesztet. Akár az Odoo-nál dolgozik, akár nem, ha valamit próbál egyesíteni az odoo/odoo, odoo/enterprise, odoo/upgrade vagy az odoo.sh-ban, át kell mennie a CI-n. Ha egy másik projekten dolgozik, érdemes megfontolni saját CI hozzáadását.

Runbot

Referencia: a témával kapcsolatos dokumentáció megtalálható a Runbot FAQ oldalon.

A tesztek többsége a Runbot rendszeren fut le minden alkalommal, amikor egy commitot feltöltenek a GitHubra.

A commit/ág állapotát a runbot irányítópulton történő szűréssel tekintheti meg.

Minden ághoz egy csomag jön létre. Egy csomag egy konfigurációból és kötegekből áll.

Egy köteg egy építési készlet, amely a csomag paramétereitől függ. Egy köteg zöld (azaz átmegy a teszteken), ha az összes építés zöld.

Egy építés akkor történik, amikor elindítunk egy szervert. Ez alépítésekre osztható. Általában vannak építések a közösségi verzióhoz, a vállalati verzióhoz (csak akkor, ha van vállalati ág, de kényszerítheti az építést), és az ág migrációjához. Egy építés zöld, ha minden alépítés zöld.

Egy alépítés csak néhány részt végez el abból, amit egy teljes építés csinál. A CI folyamat felgyorsítására használják. Általában a telepítés utáni tesztek 4 párhuzamos példányra bontására használják. Egy alépítés zöld, ha minden teszt sikeres és nincsenek hibák/figyelmeztetések naplózva.

Megjegyzés

  • Minden teszt lefut, függetlenül a végrehajtott módosításoktól. Egy elírás javítása egy hibaüzenetben vagy egy teljes modul átalakítása ugyanazokat a teszteket indítja el. Minden modult is telepítenek. Ez azt jelenti, hogy valami nem működhet, még akkor sem, ha a Runbot zöld, azaz a változtatásai egy olyan modulra támaszkodnak, amelyre a változtatások modula nem támaszkodik.

  • A lokalizációs modulok (azaz az ország-specifikus modulok) nincsenek telepítve a Runboton (kivéve az általánosat). Néhány külső függőséggel rendelkező modul is kizárható.

  • Van egy éjszakai építés, amely további teszteket futtat: modulműveletek, lokalizáció, egyetlen modul telepítések, több építés a nem determinisztikus hibákhoz stb. Ezeket nem tartják meg a standard CI-ben, hogy lerövidítsék a végrehajtási időt.

A Runbot által épített építésbe is bejelentkezhet. Három felhasználó használható: admin, demo és portal. A jelszó megegyezik a bejelentkezéssel. Ez hasznos a különböző verziók gyors teszteléséhez anélkül, hogy helyben kellene építeni. A teljes naplók is elérhetők; ezeket a megfigyeléshez használják.

Robodoo

Valószínűleg még egy kis tapasztalatot kell szerezned, mielőtt jogot kapnál a robodoo meghívására, de azért itt van néhány megjegyzés.

Robodoo az a személy, aki a CI állapotát címkékként spammeli a PR-jeiden, de ő az is, aki kedvesen integrálja a commitjaidat a fő tárolókba.

Amikor az utolsó batch zöld, a reviewer kérheti robodoo-t, hogy egyesítse a PR-edet (ez inkább egy rebase, mint egy merge). Ezután a mergebot-hoz kerül.

Mergebot

Mergebot az utolsó tesztelési fázis egy PR egyesítése előtt.

Ez a lépés a branch-ed commitjait veszi, amelyek még nincsenek jelen a célon, előkészíti és újra futtatja a teszteket még egyszer, beleértve az enterprise verziót is, még akkor is, ha csak valamit a közösségben változtatsz.

Ez a lépés Staging failed hibaüzenettel meghiúsulhat. Ennek oka lehet

  • egy nem determinisztikus hiba, amely már a célon van. Ha Odoo alkalmazott vagy, itt ellenőrizheted ezeket: https://runbot.odoo.com/runbot/errors

  • egy nem determinisztikus hiba, amelyet te vezettél be, de a CI-ben korábban nem észlelték

  • egy másik commit-tal való összeférhetetlenség, amelyet közvetlenül előtte egyesítettek, és amit Ön próbál egyesíteni

  • összeférhetetlenség az enterprise adattárral, ha csak a community adattárban végzett változtatásokat

Mindig ellenőrizze, hogy a probléma nem Öntől származik, mielőtt megkéri az egyesítő botot az újrapróbálkozásra: rebase-elje az ágát a célra, és futtassa újra a teszteket helyileg.

Modulok

Mivel az Odoo moduláris, a teszteknek is modulárisnak kell lenniük. Ez azt jelenti, hogy a tesztek abban a modulban vannak meghatározva, amely hozzáadja az Ön által hozzáadott funkciót, és a tesztek nem függhetnek olyan modulokból származó funkcióktól, amelyektől az Ön modulja nem függ.

Hivatkozás: a témával kapcsolatos dokumentáció megtalálható a Special Tags részben.

from odoo.tests.common import TransactionCase
from odoo.tests import tagged

# The CI will run these tests after all the modules are installed,
# not right after installing the one defining it.
@tagged('post_install', '-at_install')  # add `post_install` and remove `at_install`
class PostInstallTestCase(TransactionCase):
    def test_01(self):
        ...

@tagged('at_install')  # this is the default
class AtInstallTestCase(TransactionCase):
    def test_01(self):
        ...

Ha a tesztelni kívánt viselkedés megváltoztatható egy másik modul telepítésével, biztosítania kell, hogy az at_install címke be legyen állítva; ellenkező esetben használhatja a post_install címkét a CI felgyorsítására, és biztosíthatja, hogy ne változzon meg, ha nem kellene.

Teszt írása

Hivatkozás: a témával kapcsolatos dokumentáció megtalálható a Python unittest és a Testing Odoo részben.

Íme néhány dolog, amit figyelembe kell venni a teszt írása előtt

  • A teszteknek függetleneknek kell lenniük az adatbázisban jelenleg lévő adatoktól (beleértve a demó adatokat is)

  • A tesztek nem befolyásolhatják az adatbázist azáltal, hogy maradványadatokat hagynak/módosítanak. Ezt általában a tesztkeretrendszer végzi el egy visszagörgetéssel. Ezért soha nem szabad meghívni a cr.commit-et egy tesztben (sem máshol az üzleti kódban).

  • Egy hibajavítás esetén a tesztnek meg kell buknia a javítás alkalmazása előtt, és sikeresnek kell lennie utána.

  • Ne tesztelj olyasmit, amit már máshol teszteltek; bízhatsz az ORM-ben. Az üzleti modulok legtöbb tesztjének csak az üzleti folyamatokat kell tesztelnie.

  • Nem kell adatokat az adatbázisba önteni.

Megjegyzés

Remember that onchange only applies in the Form views, not by changing the attributes in python. This also applies in the tests. If you want to emulate a Form view, you can use odoo.tests.Form.

A teszteknek a modul gyökerében lévő tests mappában kell lenniük. Minden tesztfájlnévnek test_-tel kell kezdődnie, és importálva kell lennie a tesztmappa __init__.py-jában. Nem szabad importálni a tesztmappát/modult a modul __init__.py-jában.

estate
├── models
│   ├── *.py
│   └── __init__.py
├── tests
│   ├── test_*.py
│   └── __init__.py
├── __init__.py
└── __manifest__.py

Minden tesztnek az odoo.tests.common.TransactionCase-t kell kiterjesztenie. Általában definiálsz egy setUpClass-t és a teszteket. A setUpClass megírása után egy env áll rendelkezésre az osztályban, és elkezdhetsz interakcióba lépni az ORM-mel.

Ezek a tesztosztályok a unittest python modulra épülnek.

from odoo.tests.common import TransactionCase
from odoo.exceptions import UserError
from odoo.tests import tagged

# The CI will run these tests after all the modules are installed,
# not right after installing the one defining it.
@tagged('post_install', '-at_install')
class EstateTestCase(TransactionCase):

    @classmethod
    def setUpClass(cls):
        # add env on cls and many other things
        super(EstateTestCase, cls).setUpClass()

        # create the data for each tests. By doing it in the setUpClass instead
        # of in a setUp or in each test case, we reduce the testing time and
        # the duplication of code.
        cls.properties = cls.env['estate.property'].create([...])

    def test_creation_area(self):
        """Test that the total_area is computed like it should."""
        self.properties.living_area = 20
        self.assertRecordValues(self.properties, [
           {'name': ..., 'total_area': ...},
           {'name': ..., 'total_area': ...},
        ])


    def test_action_sell(self):
        """Test that everything behaves like it should when selling a property."""
        self.properties.action_sold()
        self.assertRecordValues(self.properties, [
           {'name': ..., 'state': ...},
           {'name': ..., 'state': ...},
        ])

        with self.assertRaises(UserError):
            self.properties.forbidden_action_on_sold_property()

Megjegyzés

For better readability, split your tests into multiple files depending on the scope of the tests. You can also have a Common class that most of the tests should inherit from; this common class can define the whole setup for the module. For instance, in account.

Exercise

Frissítsd a kódot, hogy senki ne tudja:

  • Hozzon létre ajánlatot egy eladott ingatlanra

  • Adjon el egy ingatlant, amelyre nincs elfogadott ajánlat

és készítsen teszteket mindkét esethez. Ezenkívül ellenőrizze, hogy az eladható ingatlan eladás után helyesen van-e eladottként megjelölve.

Exercise

Valaki folyamatosan megszakítja a Kert terület és Tájolás visszaállítását, amikor kiveszi a pipát a Kert jelölőnégyzetből. Győződjön meg róla, hogy ez nem fordul elő újra.

Javaslat

Tipp: emlékezzen a Form-ról szóló megjegyzésre kicsit feljebb.