|
7 | 7 | When we execute our programs, then there are at least two things that can go wrong.
|
8 | 8 | On one hand, we can never really be sure that our program code is free of programming mistakes.
|
9 | 9 | The larger a project gets, the more likely it is that there are some bugs hidden somewhere in the code.
|
10 |
| -Thorough unit testing can reduce the likelihood of bugs, but it cannot entirely prevent them. |
| 10 | +Thorough \pglspl{unitTest} can reduce the likelihood of bugs, but it cannot entirely prevent them. |
11 | 11 |
|
12 | 12 | On the other hand, our programs do not exist all by themselves in a vacuum.
|
13 | 13 | They receive input, maybe from files, maybe from the user, maybe from sensors.
|
|
628 | 628 | \label{sec:testingExceptions}%
|
629 | 629 | %
|
630 | 630 | \gitPython{\programmingWithPythonCodeRepo}{exceptions/test_sqrt_raise.py}{--args format}{exceptions:test_sqrt_raise}{%
|
631 |
| -A unit test checking that our new variant of the \pythonil{sqrt} function given in \cref{lst:exceptions:sqrt_raise} properly raises an \pythonilIdx{ArithmeticError} if its input is non-finite or negative.}% |
| 631 | +A \pgls{unitTest} checking that our new variant of the \pythonil{sqrt} function given in \cref{lst:exceptions:sqrt_raise} properly raises an \pythonilIdx{ArithmeticError} if its input is non-finite or negative.}% |
632 | 632 | %
|
633 | 633 | \gitOutputTool{\programmingWithPythonCodeRepo}{.}{_scripts_/pytest.sh exceptions test_sqrt_raise.py}{exceptions:test_sqrt_raise:pytest}{%
|
634 |
| -The output of the unit tests in \cref{lst:exceptions:test_sqrt_raise}: % |
| 634 | +The output of the \pglspl{unitTest} in \cref{lst:exceptions:test_sqrt_raise}: % |
635 | 635 | The \pythonilsIdx{ArithmeticError} are correctly raised.}%
|
636 | 636 | %
|
637 | 637 |
|
638 |
| -Back in \cref{sec:unitTesting}, we introduced the concept of unit tests and show how the tool \pytest\ can be used to test our functions. |
639 |
| -We stated in \cref{bp:unitTestCoverage} that we should cover all the branches of the control flow inside a function with unit tests. |
| 638 | +Back in \cref{sec:unitTesting}, we introduced the concept of \pglspl{unitTest} and show how the tool \pytest\ can be used to test our functions. |
| 639 | +We stated in \cref{bp:unitTestCoverage} that we should cover all the branches of the control flow inside a function with \pglspl{unitTest}. |
640 | 640 | One kind of branch that is often overlooked are \pythonilsIdx{Exception} and extension handling~\cite{LRBP2021AEHTPIOSL}.
|
641 | 641 |
|
642 |
| -If our function is supposed to \pythonilIdx{raise} a certain exception in some cases, then we should have a unit test that checks if this \pythonilsIdx{Exception} is actually raised as it should be. |
643 |
| -Now, any exception raised by a unit test will cause the test to fail. |
| 642 | +If our function is supposed to \pythonilIdx{raise} a certain exception in some cases, then we should have a \pgls{unitTest} that checks if this \pythonilsIdx{Exception} is actually raised as it should be. |
| 643 | +Now, any exception raised by a \pgls{unitTest} will cause the test to fail. |
644 | 644 | This seems to contradict our goal to intentionally raise the exceptions.
|
645 | 645 | Luckily, \pytest\ offers us a device for this.
|
646 | 646 |
|
|
652 | 652 | If it is raised, the text succeeds.
|
653 | 653 |
|
654 | 654 | \gitPython{\programmingWithPythonCodeRepo}{exceptions/test_sqrt.py}{--args format}{exceptions:test_sqrt}{%
|
655 |
| -Two unit tests checking the original variant of the \pythonil{sqrt} function from back in \cref{lst:functions:test_my_math_2} that does not raise errors.}% |
| 655 | +Two \pglspl{unitTest} checking the original variant of the \pythonil{sqrt} function from back in \cref{lst:functions:test_my_math_2} that does not raise errors.}% |
656 | 656 | %
|
657 | 657 | \gitOutputTool{\programmingWithPythonCodeRepo}{.}{_scripts_/pytest.sh exceptions test_sqrt.py}{exceptions:test_sqrt:pytest}{%
|
658 |
| -The output of the unit tests in \cref{lst:exceptions:test_sqrt}: % |
| 658 | +The output of the \pglspl{unitTest} in \cref{lst:exceptions:test_sqrt}: % |
659 | 659 | No error was raised in it, so the first fails and the error message in the second test does not fit, so it fails as well.}%
|
660 | 660 | %
|
661 | 661 | In particular, we can provide the exception class as well as a \pgls{regex} via the parameter~\pythonil{match} to \pythonilIdx{raises}.
|
|
676 | 676 | Therefore, our produced error message must follow this pattern for the test to work.
|
677 | 677 | And, as you can find in the \pytest\ output in \cref{exec:exceptions:test_sqrt_raise:pytest}, for the values \pythonil{v in [-1.0, inf, -inf, nan]}, no error is reported.
|
678 | 678 | For these values, our \pythonil{sqrt} function does indeed raise\pythonIdx{raise} the expected \pythonilsIdx{Exception}, with the expected error messages.
|
679 |
| -The unit test succeeds.% |
| 679 | +The \pgls{unitTest} succeeds.% |
680 | 680 | \end{sloppypar}%
|
681 | 681 | %
|
682 | 682 | In \cref{lst:exceptions:test_sqrt}, we write a similar test.
|
683 | 683 | This time, we use basically the original version of our \pythonil{sqrt} function which does not by itself raise any exception.
|
684 | 684 | This function is directly implemented in the listing, in the same way as we did in \cref{lst:functions:my_math_2}, and again called \pythonil{sqrt}.
|
685 |
| -We also write two unit tests into the new file \textil{test_sqrt.py}. |
| 685 | +We also write two \pglspl{unitTest} into the new file \textil{test_sqrt.py}. |
686 | 686 | Both are intentionally designed to show what happens if either an expected exception is not raised~(\pythonil{test_sqrt_1}) or if its error message does not match the \pythonil{match} argument~(\pythonil{test_sqrt_2}).%
|
687 | 687 | %
|
688 | 688 | \begin{sloppypar}%
|
|
705 | 705 | So indeed, this does fulfill our testing requirement:
|
706 | 706 | If an \pythonilsIdx{OverflowError} is also a \pythonilIdx{ArithmeticError}, so the right type of exception was raised.
|
707 | 707 | However, its error message will not fit to our \pythonil{match} argument.
|
708 |
| -Therefore, the unit test still fails. |
| 708 | +Therefore, the \pgls{unitTest} still fails. |
709 | 709 | The output of \cref{exec:exceptions:test_sqrt:pytest} explains this clearly.%
|
710 | 710 | \end{sloppypar}%
|
711 | 711 | %
|
|
727 | 727 | %
|
728 | 728 | This allows us to cover both the expected and correct use of our function with tests as well as unexpected incorrect uses.
|
729 | 729 | We can then be confident that our code is unlikely to cause harm, neither due to bugs created by ourselves nor due to accidental misuse by other programmers due to misunderstandings (which would immediately signaled to them by \pythonilsIdx{Exception}).
|
730 |
| -Notice that good unit testing goes hand in hand with good documentation in \pglspl{docstring}, because good \pglspl{docstring} reduce the chance of such misunderstandings.% |
| 730 | +Notice that good \pglspl{unitTest} go hand in hand with good documentation in \pglspl{docstring}, because good \pglspl{docstring} reduce the chance of such misunderstandings.% |
731 | 731 | %
|
732 | 732 | \bestPractice{testAll}{%
|
733 | 733 | It is important to cover both the reasonable expected use of our functions as well as unexpected use with incorrect arguments with test cases. %
|
734 |
| -The latter case should raise\pythonIdx{raise} \pythonilsIdx{Exception}, which we should verify with unit tests.% |
| 734 | +The latter case should raise\pythonIdx{raise} \pythonilsIdx{Exception}, which we should verify with \pglspl{unitTest}.% |
735 | 735 | }%
|
736 | 736 | %
|
737 | 737 | \FloatBarrier%
|
|
865 | 865 |
|
866 | 866 | Error handling in \python\ therefore allows us to develop software that is both robust and that clearly indicates if something goes wrong.
|
867 | 867 | Of course, for software to be called \emph{robust}, it has to be tested.
|
868 |
| -Luckily, \pytest\ offers us also unit testing capabilities that check whether \pythonilsIdx{Exceptions} are raised where expected. |
| 868 | +Luckily, \pytest\ offers us also \pgls{unitTest} capabilities that check whether \pythonilsIdx{Exceptions} are raised where expected. |
869 | 869 | This completes our discussion of the error-related control flow.%
|
870 | 870 | \endhsection%
|
871 | 871 | %
|
|
0 commit comments