Skip to content

Commit b4c1acf

Browse files
clatapiegerma89RobPasMuePipKat
authored
Adding unit testing section (#1621)
* Adding unit testing section * Apply suggestions from code review Co-authored-by: German <[email protected]> Co-authored-by: Roberto Pastor Muela <[email protected]> * Mention of integration tests and CI/CD * Adding pytests examples * Update doc/source/contribution_and_api/unit_testing.rst Co-authored-by: Roberto Pastor Muela <[email protected]> * Apply suggestions from code review Co-authored-by: Roberto Pastor Muela <[email protected]> * Apply suggestions from code review Co-authored-by: German <[email protected]> * Apply suggestions from code review Co-authored-by: German <[email protected]> * Apply suggestions from code review * Formatting of the code * Apply suggestions from code review Co-authored-by: Roberto Pastor Muela <[email protected]> * Apply suggestions from code review Co-authored-by: Kathy Pippert <[email protected]> * Update doc/source/contribution_and_api/unit_testing.rst Co-authored-by: Kathy Pippert <[email protected]> * Apply suggestions from code review Co-authored-by: Kathy Pippert <[email protected]> * Changing titles Co-authored-by: German <[email protected]> Co-authored-by: Roberto Pastor Muela <[email protected]> Co-authored-by: Kathy Pippert <[email protected]>
1 parent aab9d49 commit b4c1acf

File tree

5 files changed

+179
-2
lines changed

5 files changed

+179
-2
lines changed

doc/source/contribution_and_api/index.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,6 @@ MAPDL commands mapped to PyMAPDL, see :ref:`ref_mapdl_commands`.
123123

124124
commands
125125
database
126-
building_example
127126
geometry
128127
helper
129128
inline
@@ -138,3 +137,5 @@ MAPDL commands mapped to PyMAPDL, see :ref:`ref_mapdl_commands`.
138137
post
139138
solution
140139
xpl
140+
building_example
141+
unit_testing
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
.. _ref_unit_testing_contributing:
2+
3+
Unit Testing
4+
============
5+
6+
Unit tests validate the software by testing that the logic
7+
implemented inside a certain method, class, or module is
8+
working as expected. They should be as atomic and
9+
independent as possible.
10+
11+
Unit testing is highly important. The tests check that code
12+
changes are consistent with other parts of the code
13+
and verify that these changes are implemented properly.
14+
15+
Unit tests are in the `tests <pymapdl_tests_>`_ directory in this repository,
16+
along with integration tests. The difference between
17+
a unit test and an integration test is that the latter
18+
tests several units of the code to ensure that they all work together.
19+
20+
To verify that all code is properly tested, you must ensure that every piece
21+
of code is used (covered) in at least one unit test. In this repository, the
22+
`Codecov <codecov_>`_ tool generates a coverage report of the
23+
committed code. It details how merging a pull request would impact coverage. It
24+
is one of the checks that must run successfully to merge code changes.
25+
26+
27+
.. figure:: ../images/codecov_increase.png
28+
:width: 400pt
29+
30+
31+
Coverage example
32+
----------------
33+
34+
To show how the coverage works, assume that you have
35+
this library:
36+
37+
**My awesome library**
38+
39+
40+
.. code:: python
41+
42+
def get_report_colors(theme):
43+
44+
if theme == 'weather':
45+
colors = ["blue", "lightblue", "grey"]
46+
elif theme == 'traffic':
47+
colors = ["red", "orange", "yellow"]
48+
else:
49+
colors = ["red", "blue", "green"]
50+
51+
return colors
52+
53+
54+
**Tests**
55+
56+
You can opt to run the tests with this configuration:
57+
58+
.. code:: python
59+
60+
def test_get_report_colors():
61+
62+
assert get_report_colors('weather') == ["blue", "lightblue", "grey"]
63+
assert get_report_colors('traffic') == ["red", "orange", "yellow"]
64+
assert get_report_colors('other') == ["red", "blue", "green"]
65+
66+
67+
Or, if a method is a bit more complex, you can split the case in different tests:
68+
69+
.. code:: python
70+
71+
def test_get_report_colors_weather():
72+
73+
assert get_report_colors('weather') == ["blue", "lightblue", "grey"]
74+
75+
def test_get_report_colors_traffic():
76+
77+
assert get_report_colors('traffic') == ["red", "orange", "yellow"]
78+
79+
def test_get_report_colors_other():
80+
81+
assert get_report_colors('other') == ["red", "blue", "green"]
82+
83+
84+
While the code coverage in either case is 100% for the function, the second case is
85+
more useful for debugging the function.
86+
87+
88+
Continuous Integration and Continuous Deployment (CI/CD) approach
89+
-----------------------------------------------------------------
90+
91+
Unit tests and integration tests are part of Continuous Integration (CI).
92+
The automation of testing, monitoring, and deployment of newly added
93+
code allows Continuous Deployment (CD) throughout the application
94+
lifecycle, providing a comprehensive CI/CD approach.
95+
96+
.. figure:: ../images/cicd.jpg
97+
:width: 300pt
98+
99+
Creation of a unit test
100+
-----------------------
101+
102+
In the PyMAPDL repository, `pytest <pytest_>`_ is used to run tests.
103+
104+
The name of a ``pytest`` file must be in the form ``test_XXX.py``, where ``XXX``
105+
is either the function, method, or class that you are testing or some other explicative
106+
name. In the command line, the ``-k`` argument can be used to filter the tests to run.
107+
For more information, see `pytest usage <pytest_usage_>`_.
108+
109+
Here are some guidelines for creating good unit tests:
110+
111+
- Assign long and descriptive names to tests.
112+
- Use the `Codecov <codecov_>`_ tool to ensure all implemented code is tested.
113+
- Check that tests return the same results each time.
114+
- Verify that tests are independent.
115+
- Write tests that verify only one part of the code at a time.
116+
- Make tests as short and fast as possible.
117+
118+
`What makes a good unit test <article_good_unit_test_>`_
119+
is an exhaustive list of tips for creating good unit tests.
120+
121+
Most PyMAPDL tests require a connection to a running instance of
122+
MAPDL, which makes them integration tests. If your test
123+
requires a running MAPDL instance, you can use the PyMAPDL
124+
`mapdl <mapdl_fixture_>`_ method in your function signature.
125+
It will be executed upstream of each test and not within all tests.
126+
127+
.. code:: python
128+
129+
def test_my_new_feature(mapdl): # pass the 'mapdl' fixture as an argument.
130+
131+
mapdl.prep7()
132+
# .... more code
133+
134+
return True # if everything goes ok until here
135+
136+
137+
Example
138+
--------
139+
140+
The `test_math.py <pymapdl_test_math_>`_ file contains the unit tests and integration tests of the `ansys.mapdl.core.math module <pymapdl_user_guide_math_>`_. These are just some of the many
141+
tests that you can find in the `test directory <pymapdl_tests_>`_.
142+
143+
Here are some examples of how you use ``pytest``:
144+
145+
.. code:: python
146+
147+
import numpy as np
148+
import ansys.mapdl.core.math as apdl_math
149+
150+
@pytest.fixture(scope="module")
151+
def mm(mapdl): # pass the 'mapdl' fixture as an argument.
152+
153+
return mapdl.math
154+
155+
def test_rand(mm): # pass the 'mm' fixture as an argument.
156+
157+
w = mm.rand(10)
158+
assert w.size == 10 # if it is False, AssertionError is raised
159+
160+
def test_matrix_addition(mm):
161+
162+
m1 = mm.rand(10, 10)
163+
m2 = mm.rand(10, 10)
164+
m3 = m1 + m2
165+
assert np.allclose(m1.asarray() + m2.asarray(), m3.asarray())
166+
# if it is False, AssertionError is raised
167+
168+
For further explanations, see the `pytest documentation <pytest_>`_.

doc/source/images/cicd.jpg

86.4 KB
Loading
39.2 KB
Loading

doc/source/links.rst

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,13 @@
5959
.. _What_is_the_Windows_Subsystem_for_Linux: https://docs.microsoft.com/en-us/windows/wsl/about
6060
.. _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/
6161
.. _disabling_firewall_on_wsl: https://github.com/cascadium/wsl-windows-toolbar-launcher#firewall-rules
62+
.. _article_good_unit_test: https://stackoverflow.com/questions/61400/what-makes-a-good-unit-test
6263

6364
.. #Github links:
6465
.. _gh_creating_pat: https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token
6566
.. _gh_centos_wsl_1: https://github.com/wsldl-pg/CentWSL/
6667
.. _gh_centos_wsl_2: https://github.com/mishamosher/CentOS-WSL/
68+
.. _codecov: https://github.com/codecov
6769

6870
.. #PyMAPDL related
6971
.. _pymapdl_main: pymapdl_docs_
@@ -76,15 +78,21 @@
7678
.. _pymapdl_dev_docs: https://dev.mapdl.docs.pyansys.com/
7779
.. _pymapdl_discussions: https://github.com/pyansys/PyMAPDL/discussions
7880
.. _pymapdl_cheatsheet: ./_assets/Cheat_Sheet_PyMAPDL.pdf
81+
.. _pymapdl_tests: https://github.com/pyansys/pymapdl/tree/main/tests
82+
.. _pymapdl_test_math: https://github.com/pyansys/pymapdl/blob/main/tests/test_math.py
83+
.. _pymapdl_user_guide_math: https://mapdl.docs.pyansys.com/user_guide/math.html
7984
.. _licensing_guide_pdf: ./_assets/lic_guide.pdf
85+
.. _mapdl_fixture: https://github.com/pyansys/pymapdl/blob/fb5fb8b6201253f1bd56bdabee60a29abee8c7d8/tests/conftest.py#L254
8086

8187
.. #Python
8288
.. _using_venv: https://docs.python.org/3/library/venv.html
8389
.. _conda: https://conda.io
90+
.. _pytest: https://docs.pytest.org/en/7.2.x/
91+
.. _pytest_usage: https://docs.pytest.org/en/7.2.x/how-to/usage.html#specifying-which-tests-to-run
8492

8593
.. #Julia
8694
.. _julia: https://julialang.org/
8795
.. _julia_windows: https://julialang.org/downloads/platform/#windows
8896
.. _julia_linux_and_freebsd: https://julialang.org/downloads/platform/#linux_and_freebsd
8997
.. _julia_macos: https://julialang.org/downloads/platform/#macos
90-
.. _pycall: https://github.com/JuliaPy/PyCall.jl
98+
.. _pycall: https://github.com/JuliaPy/PyCall.jl

0 commit comments

Comments
 (0)