Blame programming-guidelines/de/unit-testing.page

Packit 1470ea
Packit 1470ea
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="unit-testing" xml:lang="de">
Packit 1470ea
Packit 1470ea
  <info>
Packit 1470ea
    <link type="guide" xref="index#general-guidelines"/>
Packit 1470ea
Packit 1470ea
    <credit type="author copyright">
Packit 1470ea
      <name>Philip Withnall</name>
Packit 1470ea
      <email its:translate="no">philip.withnall@collabora.co.uk</email>
Packit 1470ea
      <years>2015</years>
Packit 1470ea
    </credit>
Packit 1470ea
Packit 1470ea
    <include xmlns="http://www.w3.org/2001/XInclude" href="cc-by-sa-3-0.xml"/>
Packit 1470ea
Packit 1470ea
    <desc>Designing software to be tested and writing unit tests for it</desc>
Packit 1470ea
  
Packit 1470ea
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
Packit 1470ea
      <mal:name>Mario Blättermann</mal:name>
Packit 1470ea
      <mal:email>mario.blaettermann@gmail.com</mal:email>
Packit 1470ea
      <mal:years>2016</mal:years>
Packit 1470ea
    </mal:credit>
Packit 1470ea
  
Packit 1470ea
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
Packit 1470ea
      <mal:name>Christian Kirbach</mal:name>
Packit 1470ea
      <mal:email>christian.kirbach@gmail.com</mal:email>
Packit 1470ea
      <mal:years>2016</mal:years>
Packit 1470ea
    </mal:credit>
Packit 1470ea
  </info>
Packit 1470ea
Packit 1470ea
  <title>Unit Testing</title>
Packit 1470ea
Packit 1470ea
  <synopsis>
Packit 1470ea
    <title>Zusammenfassung</title>
Packit 1470ea
Packit 1470ea
    

Packit 1470ea
      Unit testing should be the primary method of testing the bulk of code
Packit 1470ea
      written, because a unit test can be written once and run many times —
Packit 1470ea
      manual tests have to be planned once and then manually run each time.
Packit 1470ea
    

Packit 1470ea
Packit 1470ea
    

Packit 1470ea
      Development of unit tests starts with the architecture and API design of
Packit 1470ea
      the code to be tested: code should be designed to be easily testable, or
Packit 1470ea
      will potentially be very difficult to test.
Packit 1470ea
    

Packit 1470ea
Packit 1470ea
    <list>
Packit 1470ea
      <item>

Packit 1470ea
        Write unit tests to be as small as possible, but no smaller.
Packit 1470ea
        (<link xref="#writing-unit-tests"/>)
Packit 1470ea
      

</item>
Packit 1470ea
      <item>

Packit 1470ea
        Use code coverage tools to write tests to get high code coverage.
Packit 1470ea
        (<link xref="#writing-unit-tests"/>)
Packit 1470ea
      

</item>
Packit 1470ea
      <item>

Packit 1470ea
        Run all unit tests under Valgrind to check for leaks and other problems.
Packit 1470ea
        (<link xref="#leak-checking"/>)
Packit 1470ea
      

</item>
Packit 1470ea
      <item>

Packit 1470ea
        Use appropriate tools to automatically generate unit tests where
Packit 1470ea
        possible. (<link xref="#test-generation"/>)
Packit 1470ea
      

</item>
Packit 1470ea
      <item>

Packit 1470ea
        Design code to be testable from the beginning.
Packit 1470ea
        (<link xref="#writing-testable-code"/>)
Packit 1470ea
      

</item>
Packit 1470ea
    </list>
Packit 1470ea
  </synopsis>
Packit 1470ea
Packit 1470ea
  <section id="writing-unit-tests">
Packit 1470ea
    <title>Writing Unit Tests</title>
Packit 1470ea
Packit 1470ea
    

Packit 1470ea
      Unit tests should be written in conjunction with looking at
Packit 1470ea
      <link xref="tooling#gcov-and-lcov">code coverage information gained from
Packit 1470ea
      running the tests</link>. This typically means writing an initial set of
Packit 1470ea
      unit tests, running them to get coverage data, then reworking and
Packit 1470ea
      expanding them to increase the code coverage levels. Coverage should be
Packit 1470ea
      increased first by ensuring all functions are covered (at least in part),
Packit 1470ea
      and then by ensuring all lines of code are covered. By covering functions
Packit 1470ea
      first, API problems which will prevent effective testing can be found
Packit 1470ea
      quickly. These typically manifest as internal functions which cannot
Packit 1470ea
      easily be called from unit tests. Overall, coverage levels of over 90%
Packit 1470ea
      should be aimed for; don’t just test cases covered by project
Packit 1470ea
      requirements, test everything.
Packit 1470ea
    

Packit 1470ea
Packit 1470ea
    

Packit 1470ea
      Like <link xref="version-control">git commits</link>, each unit test
Packit 1470ea
      should be ‘as small as possible, but no smaller’, testing a single
Packit 1470ea
      specific API or behavior. Each test case must be able to be run
Packit 1470ea
      individually, without depending on state from other test cases. This is
Packit 1470ea
      important to allow debugging of a single failing test, without having to
Packit 1470ea
      step through all the other test code as well. It also means that a single
Packit 1470ea
      test failure can easily be traced back to a specific API, rather than a
Packit 1470ea
      generic ‘unit tests failed somewhere’ message.
Packit 1470ea
    

Packit 1470ea
Packit 1470ea
    

Packit 1470ea
      GLib has support for unit testing with its
Packit 1470ea
      <link href="https://developer.gnome.org/glib/stable/glib-Testing.html">GTest
Packit 1470ea
      framework</link>, allowing tests to be arranged in groups and hierarchies.
Packit 1470ea
      This means that groups of related tests can be run together for enhanced
Packit 1470ea
      debugging too, by running the test binary with the <cmd>-p</cmd> argument:
Packit 1470ea
      <cmd>./test-suite-name -p /path/to/test/group</cmd>.
Packit 1470ea
    

Packit 1470ea
  </section>
Packit 1470ea
Packit 1470ea
  <section id="installed-tests">
Packit 1470ea
    <title>Installierte Tests</title>
Packit 1470ea
Packit 1470ea
    

Packit 1470ea
      All unit tests should be installed system-wide, following the
Packit 1470ea
      <link href="https://wiki.gnome.org/Initiatives/GnomeGoals/InstalledTests">installed-tests
Packit 1470ea
      standard</link>.
Packit 1470ea
    

Packit 1470ea
Packit 1470ea
    

Packit 1470ea
      By installing the unit tests, continuous integration (CI) is made easier,
Packit 1470ea
      since tests for one project can be re-run after changes to other projects
Packit 1470ea
      in the CI environment, thus testing the interfaces between modules. That
Packit 1470ea
      is useful for a highly-coupled set of projects like GNOME.
Packit 1470ea
    

Packit 1470ea
Packit 1470ea
    

Packit 1470ea
      To add support for installed-tests, add the following to
Packit 1470ea
      <file>configure.ac</file>:
Packit 1470ea
    

Packit 1470ea
    # Installed tests
Packit 1470ea
AC_ARG_ENABLE([modular_tests],
Packit 1470ea
              AS_HELP_STRING([--disable-modular-tests],
Packit 1470ea
                             [Disable build of test programs (default: no)]),,
Packit 1470ea
              [enable_modular_tests=yes])
Packit 1470ea
AC_ARG_ENABLE([installed_tests],
Packit 1470ea
              AS_HELP_STRING([--enable-installed-tests],
Packit 1470ea
                             [Install test programs (default: no)]),,
Packit 1470ea
              [enable_installed_tests=no])
Packit 1470ea
AM_CONDITIONAL([BUILD_MODULAR_TESTS],
Packit 1470ea
               [test "$enable_modular_tests" = "yes" ||
Packit 1470ea
                test "$enable_installed_tests" = "yes"])
Packit 1470ea
AM_CONDITIONAL([BUILDOPT_INSTALL_TESTS],[test "$enable_installed_tests" = "yes"])
Packit 1470ea
Packit 1470ea
    

Packit 1470ea
      Then in <file>tests/Makefile.am</file>:
Packit 1470ea
    

Packit 1470ea
    insttestdir = $(libexecdir)/installed-tests/[project]
Packit 1470ea
Packit 1470ea
all_test_programs = \
Packit 1470ea
	test-program1 \
Packit 1470ea
	test-program2 \
Packit 1470ea
	test-program3 \
Packit 1470ea
	$(NULL)
Packit 1470ea
if BUILD_MODULAR_TESTS
Packit 1470ea
TESTS = $(all_test_programs)
Packit 1470ea
noinst_PROGRAMS = $(TESTS)
Packit 1470ea
endif
Packit 1470ea
Packit 1470ea
if BUILDOPT_INSTALL_TESTS
Packit 1470ea
insttest_PROGRAMS = $(all_test_programs)
Packit 1470ea
Packit 1470ea
testmetadir = $(datadir)/installed-tests/[project]
Packit 1470ea
testmeta_DATA = $(all_test_programs:=.test)
Packit 1470ea
Packit 1470ea
testdatadir = $(insttestdir)
Packit 1470ea
testdata_DATA = $(test_files)
Packit 1470ea
Packit 1470ea
testdata_SCRIPTS = $(test_script_files)
Packit 1470ea
endif
Packit 1470ea
Packit 1470ea
EXTRA_DIST = $(test_files)
Packit 1470ea
Packit 1470ea
%.test: % Makefile
Packit 1470ea
	$(AM_V_GEN) (echo '[Test]' > $@.tmp; \
Packit 1470ea
	echo 'Type=session' >> $@.tmp; \
Packit 1470ea
	echo 'Exec=$(insttestdir)/$<' >> $@.tmp; \
Packit 1470ea
	mv $@.tmp $@)
Packit 1470ea
  </section>
Packit 1470ea
Packit 1470ea
  <section id="leak-checking">
Packit 1470ea
    <title>Leak Checking</title>
Packit 1470ea
Packit 1470ea
    

Packit 1470ea
      Once unit tests with high code coverage have been written, they can be run
Packit 1470ea
      under various dynamic analysis tools, such as
Packit 1470ea
      <link xref="tooling#valgrind">Valgrind</link> to check for leaks,
Packit 1470ea
      threading errors, allocation problems, etc. across the entire code base.
Packit 1470ea
      The higher the code coverage of the unit tests, the more confidence the
Packit 1470ea
      Valgrind results can be treated with. See <link xref="tooling"/> for more
Packit 1470ea
      information, including build system integration instructions.
Packit 1470ea
    

Packit 1470ea
Packit 1470ea
    

Packit 1470ea
      Critically, this means that unit tests should not leak memory or other
Packit 1470ea
      resources themselves, and similarly should not have any threading
Packit 1470ea
      problems. Any such problems would effectively be false positives in the
Packit 1470ea
      analysis of the actual project code. (False positives which need to be
Packit 1470ea
      fixed by fixing the unit tests.)
Packit 1470ea
    

Packit 1470ea
  </section>
Packit 1470ea
Packit 1470ea
  <section id="test-generation">
Packit 1470ea
    <title>Test Generation</title>
Packit 1470ea
Packit 1470ea
    

Packit 1470ea
      Certain types of code are quite repetitive, and require a lot of unit
Packit 1470ea
      tests to gain good coverage; but are appropriate for
Packit 1470ea
      <link href="http://en.wikipedia.org/wiki/Test_data_generation">test data
Packit 1470ea
      generation</link>, where a tool is used to automatically generate test
Packit 1470ea
      vectors for the code. This can drastically reduce the time needed for
Packit 1470ea
      writing unit tests, for code in these specific domains.
Packit 1470ea
    

Packit 1470ea
Packit 1470ea
    <section id="json">
Packit 1470ea
      <title>JSON</title>
Packit 1470ea
Packit 1470ea
      

Packit 1470ea
        One example of a domain amenable to test data generation is parsing,
Packit 1470ea
        where the data to be parsed is required to follow a strict schema — this
Packit 1470ea
        is the case for XML and JSON documents. For JSON, a tool such as
Packit 1470ea
        <link href="http://people.collabora.com/~pwith/walbottle/">Walbottle</link>
Packit 1470ea
        can be used to generate test vectors for all types of valid and invalid
Packit 1470ea
        input according to the schema.
Packit 1470ea
      

Packit 1470ea
Packit 1470ea
      

Packit 1470ea
        Every type of JSON document should have a
Packit 1470ea
        <link href="http://json-schema.org/">JSON Schema</link> defined for it,
Packit 1470ea
        which can then be passed to Walbottle to generate test vectors:
Packit 1470ea
      

Packit 1470ea
      
Packit 1470ea
json-schema-generate --valid-only schema.json
Packit 1470ea
json-schema-generate --invalid-only schema.json
Packit 1470ea
Packit 1470ea
      

Packit 1470ea
        These test vectors can then be passed to the code under test in its unit
Packit 1470ea
        tests. The JSON instances generated by <cmd>--valid-only</cmd> should be
Packit 1470ea
        accepted; those from <cmd>--invalid-only</cmd> should be rejected.
Packit 1470ea
      

Packit 1470ea
    </section>
Packit 1470ea
  </section>
Packit 1470ea
Packit 1470ea
  <section id="writing-testable-code">
Packit 1470ea
    <title>Writing Testable Code</title>
Packit 1470ea
Packit 1470ea
    

Packit 1470ea
      Code should be written with testability in mind from the design stage, as
Packit 1470ea
      it affects API design and architecture in fundamental ways. A few key
Packit 1470ea
      principles:
Packit 1470ea
    

Packit 1470ea
    <list>
Packit 1470ea
      <item>

Packit 1470ea
        Do not use global state. Singleton objects are usually a bad idea as
Packit 1470ea
        they can’t be instantiated separately or controlled in the unit tests.
Packit 1470ea
      

</item>
Packit 1470ea
      <item>

Packit 1470ea
        Separate out use of external state, such as databases, networking, or
Packit 1470ea
        the file system. The unit tests can then replace the accesses to
Packit 1470ea
        external state with mocked objects. A common approach to this is to use
Packit 1470ea
        dependency injection to pass a file system wrapper object to the code
Packit 1470ea
        under test. For example, a class should not load a global database (from
Packit 1470ea
        a fixed location in the file system) because the unit tests would then
Packit 1470ea
        potentially overwrite the running system’s copy of the database, and
Packit 1470ea
        could never be executed in parallel. They should be passed an object
Packit 1470ea
        which provides an interface to the database: in a production system,
Packit 1470ea
        this would be a thin wrapper around the database API; for testing, it
Packit 1470ea
        would be a mock object which checks the requests given to it and returns
Packit 1470ea
        hard-coded responses for various tests.
Packit 1470ea
      

</item>
Packit 1470ea
      <item>

Packit 1470ea
        Expose utility functions where they might be generally useful.
Packit 1470ea
      

</item>
Packit 1470ea
      <item>

Packit 1470ea
        Split projects up into collections of small, private libraries which are
Packit 1470ea
        then linked together with a minimal amount of glue code into the overall
Packit 1470ea
        executable. Each can be tested separately.
Packit 1470ea
      

</item>
Packit 1470ea
    </list>
Packit 1470ea
  </section>
Packit 1470ea
Packit 1470ea
  <section id="external-links">
Packit 1470ea
    <title>Externe Links</title>
Packit 1470ea
Packit 1470ea
    

Packit 1470ea
      The topic of software testability is covered in the following articles:
Packit 1470ea
    

Packit 1470ea
    <list>
Packit 1470ea
      <item>

<link href="http://msdn.microsoft.com/en-us/magazine/dd263069.aspx">Design for testability</link>

</item>
Packit 1470ea
      <item>

<link href="http://en.wikipedia.org/wiki/Software_testability">Software testability</link>

</item>
Packit 1470ea
      <item>

<link href="http://en.wikipedia.org/wiki/Dependency_injection">Dependency injection</link>

</item>
Packit 1470ea
      <item>

<link href="http://c2.com/cgi/wiki?SoftwareDesignForTesting">Software design for testing</link>

</item>
Packit 1470ea
    </list>
Packit 1470ea
  </section>
Packit 1470ea
</page>