diff --git a/doc/source/contribution_and_api/index.rst b/doc/source/contribution_and_api/index.rst index 390fb178a4..90acb937f9 100644 --- a/doc/source/contribution_and_api/index.rst +++ b/doc/source/contribution_and_api/index.rst @@ -123,7 +123,6 @@ MAPDL commands mapped to PyMAPDL, see :ref:`ref_mapdl_commands`. commands database - building_example geometry helper inline @@ -138,3 +137,5 @@ MAPDL commands mapped to PyMAPDL, see :ref:`ref_mapdl_commands`. post solution xpl + building_example + unit_testing diff --git a/doc/source/contribution_and_api/unit_testing.rst b/doc/source/contribution_and_api/unit_testing.rst new file mode 100644 index 0000000000..cdd59abc8f --- /dev/null +++ b/doc/source/contribution_and_api/unit_testing.rst @@ -0,0 +1,168 @@ +.. _ref_unit_testing_contributing: + +Unit Testing +============ + +Unit tests validate the software by testing that the logic +implemented inside a certain method, class, or module is +working as expected. They should be as atomic and +independent as possible. + +Unit testing is highly important. The tests check that code +changes are consistent with other parts of the code +and verify that these changes are implemented properly. + +Unit tests are in the `tests `_ directory in this repository, +along with integration tests. The difference between +a unit test and an integration test is that the latter +tests several units of the code to ensure that they all work together. + +To verify that all code is properly tested, you must ensure that every piece +of code is used (covered) in at least one unit test. In this repository, the +`Codecov `_ tool generates a coverage report of the +committed code. It details how merging a pull request would impact coverage. It +is one of the checks that must run successfully to merge code changes. + + +.. figure:: ../images/codecov_increase.png + :width: 400pt + + +Coverage example +---------------- + +To show how the coverage works, assume that you have +this library: + +**My awesome library** + + +.. code:: python + + def get_report_colors(theme): + + if theme == 'weather': + colors = ["blue", "lightblue", "grey"] + elif theme == 'traffic': + colors = ["red", "orange", "yellow"] + else: + colors = ["red", "blue", "green"] + + return colors + + +**Tests** + +You can opt to run the tests with this configuration: + +.. code:: python + + def test_get_report_colors(): + + assert get_report_colors('weather') == ["blue", "lightblue", "grey"] + assert get_report_colors('traffic') == ["red", "orange", "yellow"] + assert get_report_colors('other') == ["red", "blue", "green"] + + +Or, if a method is a bit more complex, you can split the case in different tests: + +.. code:: python + + def test_get_report_colors_weather(): + + assert get_report_colors('weather') == ["blue", "lightblue", "grey"] + + def test_get_report_colors_traffic(): + + assert get_report_colors('traffic') == ["red", "orange", "yellow"] + + def test_get_report_colors_other(): + + assert get_report_colors('other') == ["red", "blue", "green"] + + +While the code coverage in either case is 100% for the function, the second case is +more useful for debugging the function. + + +Continuous Integration and Continuous Deployment (CI/CD) approach +----------------------------------------------------------------- + +Unit tests and integration tests are part of Continuous Integration (CI). +The automation of testing, monitoring, and deployment of newly added +code allows Continuous Deployment (CD) throughout the application +lifecycle, providing a comprehensive CI/CD approach. + +.. figure:: ../images/cicd.jpg + :width: 300pt + +Creation of a unit test +----------------------- + +In the PyMAPDL repository, `pytest `_ is used to run tests. + +The name of a ``pytest`` file must be in the form ``test_XXX.py``, where ``XXX`` +is either the function, method, or class that you are testing or some other explicative +name. In the command line, the ``-k`` argument can be used to filter the tests to run. +For more information, see `pytest usage `_. + +Here are some guidelines for creating good unit tests: + +- Assign long and descriptive names to tests. +- Use the `Codecov `_ tool to ensure all implemented code is tested. +- Check that tests return the same results each time. +- Verify that tests are independent. +- Write tests that verify only one part of the code at a time. +- Make tests as short and fast as possible. + +`What makes a good unit test `_ +is an exhaustive list of tips for creating good unit tests. + +Most PyMAPDL tests require a connection to a running instance of +MAPDL, which makes them integration tests. If your test +requires a running MAPDL instance, you can use the PyMAPDL +`mapdl `_ method in your function signature. +It will be executed upstream of each test and not within all tests. + +.. code:: python + + def test_my_new_feature(mapdl): # pass the 'mapdl' fixture as an argument. + + mapdl.prep7() + # .... more code + + return True # if everything goes ok until here + + +Example +-------- + +The `test_math.py `_ file contains the unit tests and integration tests of the `ansys.mapdl.core.math module `_. These are just some of the many +tests that you can find in the `test directory `_. + +Here are some examples of how you use ``pytest``: + +.. code:: python + + import numpy as np + import ansys.mapdl.core.math as apdl_math + + @pytest.fixture(scope="module") + def mm(mapdl): # pass the 'mapdl' fixture as an argument. + + return mapdl.math + + def test_rand(mm): # pass the 'mm' fixture as an argument. + + w = mm.rand(10) + assert w.size == 10 # if it is False, AssertionError is raised + + def test_matrix_addition(mm): + + m1 = mm.rand(10, 10) + m2 = mm.rand(10, 10) + m3 = m1 + m2 + assert np.allclose(m1.asarray() + m2.asarray(), m3.asarray()) + # if it is False, AssertionError is raised + +For further explanations, see the `pytest documentation `_. \ No newline at end of file diff --git a/doc/source/images/cicd.jpg b/doc/source/images/cicd.jpg new file mode 100644 index 0000000000..283609c62f Binary files /dev/null and b/doc/source/images/cicd.jpg differ diff --git a/doc/source/images/codecov_increase.png b/doc/source/images/codecov_increase.png new file mode 100644 index 0000000000..35a6213f72 Binary files /dev/null and b/doc/source/images/codecov_increase.png differ diff --git a/doc/source/links.rst b/doc/source/links.rst index 283d657aa8..c4d90618b3 100644 --- a/doc/source/links.rst +++ b/doc/source/links.rst @@ -59,11 +59,13 @@ .. _What_is_the_Windows_Subsystem_for_Linux: https://docs.microsoft.com/en-us/windows/wsl/about .. _open_port_windows_10: https://answers.microsoft.com/en-us/windows/forum/all/how-to-open-port-in-windows-10-firewall/f38f67c8-23e8-459d-9552-c1b94cca579a/ .. _disabling_firewall_on_wsl: https://github.com/cascadium/wsl-windows-toolbar-launcher#firewall-rules +.. _article_good_unit_test: https://stackoverflow.com/questions/61400/what-makes-a-good-unit-test .. #Github links: .. _gh_creating_pat: https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token .. _gh_centos_wsl_1: https://github.com/wsldl-pg/CentWSL/ .. _gh_centos_wsl_2: https://github.com/mishamosher/CentOS-WSL/ +.. _codecov: https://github.com/codecov .. #PyMAPDL related .. _pymapdl_main: pymapdl_docs_ @@ -76,15 +78,21 @@ .. _pymapdl_dev_docs: https://dev.mapdl.docs.pyansys.com/ .. _pymapdl_discussions: https://github.com/pyansys/PyMAPDL/discussions .. _pymapdl_cheatsheet: ./_assets/Cheat_Sheet_PyMAPDL.pdf +.. _pymapdl_tests: https://github.com/pyansys/pymapdl/tree/main/tests +.. _pymapdl_test_math: https://github.com/pyansys/pymapdl/blob/main/tests/test_math.py +.. _pymapdl_user_guide_math: https://mapdl.docs.pyansys.com/user_guide/math.html .. _licensing_guide_pdf: ./_assets/lic_guide.pdf +.. _mapdl_fixture: https://github.com/pyansys/pymapdl/blob/fb5fb8b6201253f1bd56bdabee60a29abee8c7d8/tests/conftest.py#L254 .. #Python .. _using_venv: https://docs.python.org/3/library/venv.html .. _conda: https://conda.io +.. _pytest: https://docs.pytest.org/en/7.2.x/ +.. _pytest_usage: https://docs.pytest.org/en/7.2.x/how-to/usage.html#specifying-which-tests-to-run .. #Julia .. _julia: https://julialang.org/ .. _julia_windows: https://julialang.org/downloads/platform/#windows .. _julia_linux_and_freebsd: https://julialang.org/downloads/platform/#linux_and_freebsd .. _julia_macos: https://julialang.org/downloads/platform/#macos -.. _pycall: https://github.com/JuliaPy/PyCall.jl \ No newline at end of file +.. _pycall: https://github.com/JuliaPy/PyCall.jl