From 5aae93e635618f836900ec10733c0f2b2fe1d642 Mon Sep 17 00:00:00 2001 From: Michael <michael@buchmann.ruhr> Date: Tue, 10 Dec 2024 21:27:44 +0100 Subject: [PATCH] Added first example to plugin unit test (#8636) * Start documentation chapter for plugin tests * Added env variables to the doc * Fix style errors * Further style bugs * Reformat environment variables * Reformat environment variables * Add comments from wolflu05 * Add text to the intro * Added first example the plugin unit test * Addred line it function * Typo * Typo * Typo --- docs/docs/extend/plugins/test.md | 81 +++++++++++++++++++++++++ docs/mkdocs.yml | 1 + src/backend/InvenTree/.config.yaml.swp | Bin 16384 -> 0 bytes 3 files changed, 82 insertions(+) create mode 100644 docs/docs/extend/plugins/test.md delete mode 100644 src/backend/InvenTree/.config.yaml.swp diff --git a/docs/docs/extend/plugins/test.md b/docs/docs/extend/plugins/test.md new file mode 100644 index 0000000000..26dfbe496e --- /dev/null +++ b/docs/docs/extend/plugins/test.md @@ -0,0 +1,81 @@ +--- +Title: Unit Tests +--- + +## Unit Tests +For complicated plugins it makes sense to add unit tests the code to ensure +that plugins work correctly and are compatible with future versions too. +You can run these tests as part of your ci against the current stable and +latest tag to get notified when something breaks before it gets released as +part of stable. InvenTree offers a framework for testing. Please refer +to [Unit Tests](../../develop/contributing.md) for more information. + +### Prerequisites +For plugin testing the following environment variables must be set to True: + +| Name | Function | Value | +| --- | --- | --- | +| INVENTREE_PLUGINS_ENABLED | Enables the use of 3rd party plugins | True | +| INVENTREE_PLUGIN_TESTING | Enables enables all plugins no matter of their active state in the db or built-in flag | True | +| INVENTREE_PLUGIN_TESTING_SETUP | Enables the url mixin | True | + +### Test program + +A file called test_plugin_name.py should be added to the plugin directory. It can have the +following structure: + +``` +# Basic unit tests for the plugin +from InvenTree.unit_test import InvenTreeTestCase + +class TestMyPlugin(InvenTreeTestCase): + def test_my_function(self): + do some work here... +``` + +The test can be executed using invoke: + +``` +invoke dev.test -r module.file.class +``` + +Plugins are usually installed outside of the InventTree directory, e.g. in .local/lib/... +I that case module must be omitted. + +``` +invoke dev.test -r plugin_directory.test_plugin_name.TestMyPlugin +``` + +### do some work here... A simple Example +A simple example is shown here. Assume the plugin has a function that converts a price string +that comes from a supplier API to a float value. The price might have the form "1.456,34 €". +It can be different based on country and local settings. +The function in the plugin will convert it to a float 1456.34. It is in the class MySupplier +and has the following structure: + +``` +class MySupplier(): + + def reformat_price(self, string_price): + + ... + return float_price +``` + +This function needs to be tested. The test can look like this: + +``` +from .myplugin import MySupplier + +def test_reformat_price(self): + + self.assertEqual(MySupplier.reformat_price(self, '1.456,34 €'), 1456.34) + self.assertEqual(MySupplier.reformat_price(self, '1,45645 €'), 1.45645) + self.assertEqual(MySupplier.reformat_price(self, '1,56 $'), 1.56) + self.assertEqual(MySupplier.reformat_price(self, ''), 0) + self.assertEqual(MySupplier.reformat_price(self, 'Mumpitz'), 0) +``` + +The function assertEqual flags an error in case the two arguments are not equal. In equal case +no error is flagged and the test passes. The test function tests five different +input variations. More might be added based on the requirements. diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index f341733627..86011269e5 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -199,6 +199,7 @@ nav: - Developing a Plugin: extend/how_to_plugin.md - Model Metadata: extend/plugins/metadata.md - Tags: extend/plugins/tags.md + - Unit Test: extend/plugins/test.md - Plugin Mixins: - Action Mixin: extend/plugins/action.md - API Mixin: extend/plugins/api.md diff --git a/src/backend/InvenTree/.config.yaml.swp b/src/backend/InvenTree/.config.yaml.swp deleted file mode 100644 index c9776e1c012b221ba59656cf75c03c7118dad53d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 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 Dy|To)