You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

129 lines
4.4KB

  1. A *Hello, World* Test
  2. #####################
  3. So far, we have a simple library with a single function: ``get_greeting()``
  4. and an application that makes use of it. How can we test it?
  5. With ``dds``, similar to generating applications, creating a test requires
  6. adding a suffix to a source filename stem. Instead of ``.main``, simply
  7. add ``.test`` before the file extension.
  8. A New Test Executable
  9. *********************
  10. We'll create a test for our ``strings`` component, in a file named
  11. ``strings.test.cpp``. We'll use an ``assert`` to check our ``get_greeting()``
  12. function:
  13. .. code-block:: c++
  14. :caption: ``<root>/src/hello/strings.test.cpp``
  15. :linenos:
  16. #include <hello/strings.hpp>
  17. int main() {
  18. if (hello::get_greeting() != "Hello world!") {
  19. return 1;
  20. }
  21. }
  22. If you run ``dds build`` once again, ``dds`` will generate a test executable
  23. and run it immediately. If the test executable exits with a non-zero exit code,
  24. then it will consider the test to have failed, and ``dds`` itself will exit
  25. with a non-zero exit code.
  26. .. important::
  27. ``dds`` executes tests *in parallel* by default! If the tests need access
  28. to a shared resource, locking must be implemented manually, or the shared
  29. resource should be split.
  30. .. note::
  31. ``dds`` builds and executes tests for *every build* **by default**. The
  32. ``*.test.cpp`` tests are meant to be very fast *unit* tests, so consider
  33. their execution time carefully.
  34. If your code matches the examples so far, the above test will *fail*. Keen eyes
  35. will already know the problem, but wouldn't it be better if we had better test
  36. diagnostics?
  37. A ``test_driver``: Using *Catch2*
  38. *********************************
  39. ``dds`` ships with built-in support for the `Catch2`_ C and C++ testing
  40. framework.
  41. .. _catch2: https://github.com/catchorg/Catch2
  42. To make use of Catch as our test driver, we simply declare this intent in the
  43. ``package.json5`` file at the package root:
  44. .. code-block:: js
  45. :caption: ``<root>/package.json5``
  46. :emphasize-lines: 5
  47. {
  48. name: 'hello-dds',
  49. version: '0.1.0',
  50. namespace: 'tutorial',
  51. test_driver: 'Catch-Main',
  52. }
  53. If you now run ``dds build``, we will get a linker error for a multiply-defined
  54. ``main`` function. When setting the ``test_driver`` to ``Catch-Main``, ``dds``
  55. will compile an entrypoint separately from any particular test, and the tests
  56. will link against that entrypoint. This means we cannot provide our own
  57. ``main`` function, and should instead use Catch's ``TEST_CASE`` macro to
  58. declare our test cases.
  59. In addition to an entrypoint, ``dds`` provides a ``catch.hpp`` header that we
  60. may use in our tests, simply by ``#include``-ing the appropriate path. We'll
  61. modify our test to use the Catch test macros instead of our own logic. We'll
  62. leave the condition the same, though:
  63. .. code-block:: c++
  64. :caption: ``<root>/src/hello/strings.test.cpp``
  65. :linenos:
  66. :emphasize-lines: 3, 5-7
  67. #include <hello/strings.hpp>
  68. #include <catch2/catch.hpp>
  69. TEST_CASE("Check the greeting") {
  70. CHECK(hello::get_greeting() == "Hello world!");
  71. }
  72. Now running ``dds build`` will print more output that Catch has generated as
  73. part of test execution, and we can see the reason for the failing test::
  74. [16:41:45] [error] Test <root>/_build/test/hello/strings failed! Output:
  75. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  76. strings is a Catch v2.10.2 host application.
  77. Run with -? for options
  78. -------------------------------------------------------------------------------
  79. Check the greeting
  80. -------------------------------------------------------------------------------
  81. <root>/src/hello/strings.test.cpp:5
  82. ...............................................................................
  83. <root>/src/hello/strings.test.cpp:5: FAILED:
  84. CHECK( hello::get_greeting() == "Hello world!" )
  85. with expansion:
  86. "Hello, world!" == "Hello world!"
  87. ===============================================================================
  88. test cases: 1 | 1 failed
  89. assertions: 1 | 1 failed
  90. [dds - test output end]
  91. Now that we have the direct results of the offending expression, we can
  92. much more easily diagnose the nature of the test failure. In this case, the
  93. function returns a string containing a comma ``,`` while our expectation lacks
  94. one. If we fix either the ``get_greeting`` or the expected string, we will then
  95. see our tests pass successfully and ``dds`` will exit cleanly.