File: Testing%20and%20CTest.rst

package info (click to toggle)
cmake 4.2.1-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 152,348 kB
  • sloc: ansic: 403,894; cpp: 303,807; sh: 4,097; python: 3,582; yacc: 3,106; lex: 1,279; f90: 538; asm: 471; lisp: 375; cs: 270; java: 266; fortran: 239; objc: 215; perl: 213; xml: 198; makefile: 108; javascript: 83; pascal: 63; tcl: 55; php: 25; ruby: 22
file content (232 lines) | stat: -rw-r--r-- 6,309 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
Step 8: Testing and CTest
=========================

Testing is, historically, not the role of the build system. At best it might
have a specific target which maps to building and running the project's tests.

In the CMake ecosystem, the opposite is true. CMake's testing ecosystem is
known as CTest. This ecosystem is both deceivingly simple and incredibly
powerful. In fact it is so powerful it deserves its own full tutorial to
describe everything we could achieve with it.

This is not that tutorial. In this step, we will scratch the surface of some
of the facilities that CTest provides.

Background
^^^^^^^^^^

At its core, CTest is a task launcher which runs commands and reports if they
have returned zero or non-zero values. This is the level we will be dealing
with CTest at.

CMake provides direct integration with CTest via the :command:`enable_testing`
and :command:`add_test` commands. These allow CMake to setup the necessary
infrastructure in the build folder for CTest to discover, run, and report
on various tests we might be interested in.

After setting up and building tests, the easiest way to invoke CTest is to run
it directly on the build directory with:

.. code-block:: console

  ctest --test-dir build

Which will run all available tests. Specific tests can be run with regular
expressions.

.. code-block:: console

  ctest --test-dir build -R SpecificTest

CTest also has advanced mechanisms for scripting, fixtures, sanitizers,
job servers, metric reportings, and much more. See the :manual:`ctest(1)`
manual for more information.

Exercise 1 - Adding Tests
^^^^^^^^^^^^^^^^^^^^^^^^^

CTest convention dictates the building and running of tests be based on a
default-``ON`` variable named :variable:`BUILD_TESTING`. When using the full
suite of CTest capabilities via the :module:`CTest` module, this
:command:`option` is setup for us. When using a more stripped-down approach to
testing, it's expected the project will setup the option (or at least one of a
similar name) on its own.

When :variable:`BUILD_TESTING` is true, the :command:`enable_testing` command
should be called in the root CML.

.. code-block:: cmake

  enable_testing()

This will generate all the necessary metadata into the build tree for CTest to
find and run tests.

Once that has been done, the :command:`add_test` command can be used to create
a test anywhere in the project. The semantics of this command are similar to
:command:`add_custom_command`; we can name an executable target as the "command".

.. code-block:: cmake

  add_test(
    NAME MyAppWithTestFlag
    COMMAND MyApp --test
  )

Goal
----

Add tests for the MathFunctions library to the project and run them with CTest.

Helpful Resources
-----------------

* :variable:`BUILD_TESTING`
* :command:`enable_testing`
* :command:`function`
* :command:`add_test`

Files to Edit
-------------

* ``Tests/CMakeLists.txt``
* ``CMakeLists.txt``

Getting Started
---------------

A testing program has been written in the file ``Tests/TestMathFunctions.cxx``.
This program takes a single command line argument, the math function to be
tested, with valid values of ``add``, ``mul``, ``sqrt``, and ``sub``. The return
code is zero if the operation is recognized and the calculated value is valid,
otherwise it is non-zero.

Complete ``TODO 1`` through ``TODO 7``.

Build and Run
-------------

No special configuration is needed, configure and build as usual.

.. code-block:: console

  cmake --preset tutorial
  cmake --build build

Verify all the tests pass with CTest.

.. note::

  If using a multi-config generator, eg Visual Studio, it will be necessary to
  specify a configuration with ``ctest -C <config> <remaining flags>``, where
  ``<config>`` is a value like ``Debug`` or ``Release``. This is true whenever
  using a multi-config generator, and won't be called out specifically in
  future commands.

.. code-block:: console

  ctest --test-dir build

You can run individual tests with the :option:`-R <ctest -R>` flag.

.. code-block:: console

  ctest --test-dir build -R sqrt

Solution
--------

First we add a new executable for the tests.

.. raw:: html

  <details><summary>TODO 1-2: Click to show/hide answer</summary>

.. literalinclude:: Step9/Tests/CMakeLists.txt
  :caption: TODO 1-2: Tests/CMakeLists.txt
  :name: Tests/CMakeLists.txt-add_executable
  :language: cmake
  :start-at: add_executable
  :end-at: TestMathFunctions.cxx
  :append: )

.. raw:: html

  </details>

Then we link in the library we are testing.

.. raw:: html

  <details><summary>TODO 3: Click to show/hide answer</summary>

.. literalinclude:: Step9/Tests/CMakeLists.txt
  :caption: TODO 3: Tests/CMakeLists.txt
  :name: Tests/CMakeLists.txt-target_link_libraries
  :language: cmake
  :start-at: target_link_libraries(TestMathFunctions
  :end-at: )

.. raw:: html

  </details>

We need to call :command:`add_test` for each of the valid operations, but this
would get repetitive, so we write a :command:`function` to do it for us.

.. raw:: html

  <details><summary>TODO 4: Click to show/hide answer</summary>

.. literalinclude:: Step9/Tests/CMakeLists.txt
  :caption: TODO 4: Tests/CMakeLists.txt
  :name: Tests/CMakeLists.txt-function
  :language: cmake
  :start-at: function
  :end-at: endfunction

.. raw:: html

  </details>

Now we can use our :command:`function` to add all the tests.

.. raw:: html

  <details><summary>TODO 5: Click to show/hide answer</summary>

.. literalinclude:: Step9/Tests/CMakeLists.txt
  :caption: TODO 5: Tests/CMakeLists.txt
  :name: Tests/CMakeLists.txt-add_test
  :language: cmake
  :start-at: MathFunctionTest(add
  :end-at: MathFunctionTest(sub

.. raw:: html

  </details>

Finally, we can add the :variable:`BUILD_TESTING` option and conditionally
enable building and running tests in the top-level CML.

.. raw:: html

  <details><summary>TODO 6-7: Click to show/hide answer</summary>

.. literalinclude:: Step9/CMakeLists.txt
  :caption: TODO 6: CMakeLists.txt
  :name: CMakeLists.txt-BUILD_TESTING
  :language: cmake
  :start-at: option(BUILD_TESTING
  :end-at: option(BUILD_TESTING

.. literalinclude:: Step9/CMakeLists.txt
  :caption: TODO 7: CMakeLists.txt
  :name: CMakeLists.txt-enable_testing
  :language: cmake
  :start-at: if(BUILD_TESTING)
  :end-at: endif()

.. raw:: html

  </details>