/usr/share/help/de/programming-guidelines/unit-testing.page is in gnome-devel-docs 3.28.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 | <?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="unit-testing" xml:lang="de">
<info>
<link type="guide" xref="index#general-guidelines"/>
<credit type="author copyright">
<name>Philip Withnall</name>
<email its:translate="no">philip.withnall@collabora.co.uk</email>
<years>2015</years>
</credit>
<include xmlns="http://www.w3.org/2001/XInclude" href="cc-by-sa-3-0.xml"/>
<desc>Designing software to be tested and writing unit tests for it</desc>
<mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
<mal:name>Mario Blättermann</mal:name>
<mal:email>mario.blaettermann@gmail.com</mal:email>
<mal:years>2016</mal:years>
</mal:credit>
<mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
<mal:name>Christian Kirbach</mal:name>
<mal:email>christian.kirbach@gmail.com</mal:email>
<mal:years>2016</mal:years>
</mal:credit>
</info>
<title>Unit Testing</title>
<synopsis>
<title>Zusammenfassung</title>
<p>
Unit testing should be the primary method of testing the bulk of code
written, because a unit test can be written once and run many times —
manual tests have to be planned once and then manually run each time.
</p>
<p>
Development of unit tests starts with the architecture and API design of
the code to be tested: code should be designed to be easily testable, or
will potentially be very difficult to test.
</p>
<list>
<item><p>
Write unit tests to be as small as possible, but no smaller.
(<link xref="#writing-unit-tests"/>)
</p></item>
<item><p>
Use code coverage tools to write tests to get high code coverage.
(<link xref="#writing-unit-tests"/>)
</p></item>
<item><p>
Run all unit tests under Valgrind to check for leaks and other problems.
(<link xref="#leak-checking"/>)
</p></item>
<item><p>
Use appropriate tools to automatically generate unit tests where
possible. (<link xref="#test-generation"/>)
</p></item>
<item><p>
Design code to be testable from the beginning.
(<link xref="#writing-testable-code"/>)
</p></item>
</list>
</synopsis>
<section id="writing-unit-tests">
<title>Writing Unit Tests</title>
<p>
Unit tests should be written in conjunction with looking at
<link xref="tooling#gcov-and-lcov">code coverage information gained from
running the tests</link>. This typically means writing an initial set of
unit tests, running them to get coverage data, then reworking and
expanding them to increase the code coverage levels. Coverage should be
increased first by ensuring all functions are covered (at least in part),
and then by ensuring all lines of code are covered. By covering functions
first, API problems which will prevent effective testing can be found
quickly. These typically manifest as internal functions which cannot
easily be called from unit tests. Overall, coverage levels of over 90%
should be aimed for; don’t just test cases covered by project
requirements, test everything.
</p>
<p>
Like <link xref="version-control">git commits</link>, each unit test
should be ‘as small as possible, but no smaller’, testing a single
specific API or behavior. Each test case must be able to be run
individually, without depending on state from other test cases. This is
important to allow debugging of a single failing test, without having to
step through all the other test code as well. It also means that a single
test failure can easily be traced back to a specific API, rather than a
generic ‘unit tests failed somewhere’ message.
</p>
<p>
GLib has support for unit testing with its
<link href="https://developer.gnome.org/glib/stable/glib-Testing.html">GTest
framework</link>, allowing tests to be arranged in groups and hierarchies.
This means that groups of related tests can be run together for enhanced
debugging too, by running the test binary with the <cmd>-p</cmd> argument:
<cmd>./test-suite-name -p /path/to/test/group</cmd>.
</p>
</section>
<section id="installed-tests">
<title>Installierte Tests</title>
<p>
All unit tests should be installed system-wide, following the
<link href="https://wiki.gnome.org/Initiatives/GnomeGoals/InstalledTests">installed-tests
standard</link>.
</p>
<p>
By installing the unit tests, continuous integration (CI) is made easier,
since tests for one project can be re-run after changes to other projects
in the CI environment, thus testing the interfaces between modules. That
is useful for a highly-coupled set of projects like GNOME.
</p>
<p>
To add support for installed-tests, add the following to
<file>configure.ac</file>:
</p>
<code># Installed tests
AC_ARG_ENABLE([modular_tests],
AS_HELP_STRING([--disable-modular-tests],
[Disable build of test programs (default: no)]),,
[enable_modular_tests=yes])
AC_ARG_ENABLE([installed_tests],
AS_HELP_STRING([--enable-installed-tests],
[Install test programs (default: no)]),,
[enable_installed_tests=no])
AM_CONDITIONAL([BUILD_MODULAR_TESTS],
[test "$enable_modular_tests" = "yes" ||
test "$enable_installed_tests" = "yes"])
AM_CONDITIONAL([BUILDOPT_INSTALL_TESTS],[test "$enable_installed_tests" = "yes"])</code>
<p>
Then in <file>tests/Makefile.am</file>:
</p>
<code>insttestdir = $(libexecdir)/installed-tests/[project]
all_test_programs = \
test-program1 \
test-program2 \
test-program3 \
$(NULL)
if BUILD_MODULAR_TESTS
TESTS = $(all_test_programs)
noinst_PROGRAMS = $(TESTS)
endif
if BUILDOPT_INSTALL_TESTS
insttest_PROGRAMS = $(all_test_programs)
testmetadir = $(datadir)/installed-tests/[project]
testmeta_DATA = $(all_test_programs:=.test)
testdatadir = $(insttestdir)
testdata_DATA = $(test_files)
testdata_SCRIPTS = $(test_script_files)
endif
EXTRA_DIST = $(test_files)
%.test: % Makefile
$(AM_V_GEN) (echo '[Test]' > $@.tmp; \
echo 'Type=session' >> $@.tmp; \
echo 'Exec=$(insttestdir)/$<' >> $@.tmp; \
mv $@.tmp $@)</code>
</section>
<section id="leak-checking">
<title>Leak Checking</title>
<p>
Once unit tests with high code coverage have been written, they can be run
under various dynamic analysis tools, such as
<link xref="tooling#valgrind">Valgrind</link> to check for leaks,
threading errors, allocation problems, etc. across the entire code base.
The higher the code coverage of the unit tests, the more confidence the
Valgrind results can be treated with. See <link xref="tooling"/> for more
information, including build system integration instructions.
</p>
<p>
Critically, this means that unit tests should not leak memory or other
resources themselves, and similarly should not have any threading
problems. Any such problems would effectively be false positives in the
analysis of the actual project code. (False positives which need to be
fixed by fixing the unit tests.)
</p>
</section>
<section id="test-generation">
<title>Test Generation</title>
<p>
Certain types of code are quite repetitive, and require a lot of unit
tests to gain good coverage; but are appropriate for
<link href="http://en.wikipedia.org/wiki/Test_data_generation">test data
generation</link>, where a tool is used to automatically generate test
vectors for the code. This can drastically reduce the time needed for
writing unit tests, for code in these specific domains.
</p>
<section id="json">
<title>JSON</title>
<p>
One example of a domain amenable to test data generation is parsing,
where the data to be parsed is required to follow a strict schema — this
is the case for XML and JSON documents. For JSON, a tool such as
<link href="http://people.collabora.com/~pwith/walbottle/">Walbottle</link>
can be used to generate test vectors for all types of valid and invalid
input according to the schema.
</p>
<p>
Every type of JSON document should have a
<link href="http://json-schema.org/">JSON Schema</link> defined for it,
which can then be passed to Walbottle to generate test vectors:
</p>
<code mime="application/x-shellscript">
json-schema-generate --valid-only schema.json
json-schema-generate --invalid-only schema.json</code>
<p>
These test vectors can then be passed to the code under test in its unit
tests. The JSON instances generated by <cmd>--valid-only</cmd> should be
accepted; those from <cmd>--invalid-only</cmd> should be rejected.
</p>
</section>
</section>
<section id="writing-testable-code">
<title>Writing Testable Code</title>
<p>
Code should be written with testability in mind from the design stage, as
it affects API design and architecture in fundamental ways. A few key
principles:
</p>
<list>
<item><p>
Do not use global state. Singleton objects are usually a bad idea as
they can’t be instantiated separately or controlled in the unit tests.
</p></item>
<item><p>
Separate out use of external state, such as databases, networking, or
the file system. The unit tests can then replace the accesses to
external state with mocked objects. A common approach to this is to use
dependency injection to pass a file system wrapper object to the code
under test. For example, a class should not load a global database (from
a fixed location in the file system) because the unit tests would then
potentially overwrite the running system’s copy of the database, and
could never be executed in parallel. They should be passed an object
which provides an interface to the database: in a production system,
this would be a thin wrapper around the database API; for testing, it
would be a mock object which checks the requests given to it and returns
hard-coded responses for various tests.
</p></item>
<item><p>
Expose utility functions where they might be generally useful.
</p></item>
<item><p>
Split projects up into collections of small, private libraries which are
then linked together with a minimal amount of glue code into the overall
executable. Each can be tested separately.
</p></item>
</list>
</section>
<section id="external-links">
<title>Externe Links</title>
<p>
The topic of software testability is covered in the following articles:
</p>
<list>
<item><p><link href="http://msdn.microsoft.com/en-us/magazine/dd263069.aspx">Design for testability</link></p></item>
<item><p><link href="http://en.wikipedia.org/wiki/Software_testability">Software testability</link></p></item>
<item><p><link href="http://en.wikipedia.org/wiki/Dependency_injection">Dependency injection</link></p></item>
<item><p><link href="http://c2.com/cgi/wiki?SoftwareDesignForTesting">Software design for testing</link></p></item>
</list>
</section>
</page>
|