{"id":6448,"date":"2020-07-21T20:55:42","date_gmt":"2020-07-22T03:55:42","guid":{"rendered":"https:\/\/visualgdb.com\/w\/?p=6448"},"modified":"2020-08-28T20:21:31","modified_gmt":"2020-08-29T03:21:31","slug":"tinyembeddedtest-framework-overview","status":"publish","type":"post","link":"https:\/\/visualgdb.com\/documentation\/tests\/TinyEmbeddedTest\/","title":{"rendered":"TinyEmbeddedTest Framework Overview"},"content":{"rendered":"<p>This page provides a quick overview of the TinyEmbeddedTest framework. The framework follows the same design principles as the CppUTest and GoogleTest frameworks, and should be very easy to use if you have experience with these frameworks.<\/p>\n<h1>Test Groups and Test Cases<\/h1>\n<p>Each unit test based on the <strong>TinyEmbeddedTest<\/strong> framework is a separate function that can be tracked and launched independently. To make test selection easier, each test must belong to a test group. You can define the test groups as shown below:<\/p>\n<pre class=\"\">TEST_GROUP(DemoTestGroup)\r\n{\r\n};<\/pre>\n<p>Once a test group is defined, you can define tests using the <strong>TEST()<\/strong> macro:<\/p>\n<pre class=\"\">TEST(DemoTestGroup, UnitTest1)\r\n{\r\n    printf(\"Hello from UnitTest1\");\r\n}\r\n\r\nTEST(DemoTestGroup, UnitTest2)\r\n{\r\n    printf(\"Hello from UnitTest2\");\r\n}<\/pre>\n<p>Once you build the project defining the tests, they will appear in the Test Explorer window, organized by test groups: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/07\/tests-2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6454\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/07\/tests-2.png\" alt=\"\" width=\"450\" height=\"517\" \/><\/a><br \/>\nYou can use the Test Explorer window to select and run any arbitrary subset of tests.<\/p>\n<p>If you are running tests from command line, use the <strong>\/testregex <\/strong>argument to filter the tests that are being run. E.g. the following command line will run <strong>UnitTest1<\/strong> from both <strong>TestGroup1<\/strong> and <strong>TestGroup2<\/strong>:<\/p>\n<pre class=\"\">VisualGDB.exe \/runtests TestDemo.vgdbtestcontainer \"\/testregex:(TestGroup1|TestGroup2)::UnitTest1\"<\/pre>\n<h2>Setup and Teardown Functions<\/h2>\n<p>Test groups can define setup and teardown methods as shown below:<\/p>\n<pre class=\"\">TEST_GROUP(DemoTestGroup)\r\n{\r\n    void setup()\r\n    {\r\n        \/\/...\r\n    }\r\n    void teardown()\r\n    {\r\n        \/\/...\r\n    }\r\n    void TestSetup(TestInstance *)\r\n    {\r\n        \/\/...\r\n    }\r\n    void TestTeardown(TestInstance *)\r\n    {\r\n        \/\/...\r\n    }\r\n};<\/pre>\n<p>If you select one of more tests from a test group, the following will happen:<\/p>\n<ul>\n<li>The <strong>setup()<\/strong> callback will be called <strong>once<\/strong> per group before running the first test in the group<\/li>\n<li>The <strong>teardown()<\/strong> callback will be called once per group after running the last test in the group<\/li>\n<li>The <strong>TestSetup()<\/strong> and <strong>TestTeardown()<\/strong> methods will be called before\/after each test<\/li>\n<\/ul>\n<h2>Assertion Macros<\/h2>\n<p>TinyEmbeddedTest provides several assertion macros inspired by the CppUTest framework. E.g. <strong>CHECK()<\/strong>, <strong>CHECK_EQUAL()<\/strong>, etc. The demo test project created by the VisualGDB wizard includes a quick demonstration of all supported assertion macros:<\/p>\n<pre class=\"\">TEST(DemoTestGroup, SuccessfulTest1)\r\n{\r\n    CHECK(true);\r\n    CHECK_FALSE(false);\r\n    CHECK_EQUAL(1, 1);\r\n    STRCMP_EQUAL(\"abc\", \"abc\");\r\n    STRNCMP_EQUAL(\"abc1\", \"abc2\", 3);\r\n    STRCMP_NOCASE_EQUAL(\"abc\", \"ABC\");\r\n    STRCMP_CONTAINS(\"123\", \"test123\");\r\n\r\n    LONGS_EQUAL(-2, -2);\r\n    UNSIGNED_LONGS_EQUAL(3, 3);\r\n    UNSIGNED_LONGS_EQUAL_WITHIN(10, 11, 2);\r\n\r\n    BYTES_EQUAL(-1, 255);\r\n    POINTERS_EQUAL(0, 0);\r\n    MEMCMP_EQUAL(\"string\", \"string\", 6);\r\n\r\n    DOUBLES_EQUAL(1.0, -1.0, 2);\r\n    DOUBLES_NOT_EQUAL(1.0, -1.0, 1);\r\n\r\n    FLOATS_EQUAL(1.0F, -1.0F, 2);   \r\n    FLOATS_NOT_EQUAL(1.0F, -1.0F, 1);\r\n\r\n    BITS_EQUAL(0x050, 0xF5F, 0x0F0);\r\n}<\/pre>\n<p>You can define custom assertion macros as well. If the assertion fails, the macro should call the printf-like <strong>ReportTestFailure()<\/strong> function. The message passed to that function will be displayed in the test failure summary in Solution Explorer.<\/p>\n<h2>Recovering from Assertion Failures<\/h2>\n<p>The default TinyEmbeddedTest behavior when a unit test fails is to continue executing the test method, assuming that it will handle this properly. You can change this behavior via <strong>VisualGDB Project Properties -&gt; Unit Tests<\/strong>:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/07\/fail.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6455\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/07\/fail.png\" alt=\"\" width=\"940\" height=\"348\" \/><\/a>TinyEmbeddedTest supports 3 different ways of handling a failed test assertion:<\/p>\n<table style=\"border-collapse: collapse; width: 100%;\" border=\"1\">\n<tbody>\n<tr>\n<td style=\"width: 33.3333%;\">Mode<\/td>\n<td style=\"width: 33.3333%;\">Pros<\/td>\n<td style=\"width: 33.3333%;\">Cons<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 33.3333%;\">Test continues running<\/td>\n<td style=\"width: 33.3333%;\">Minimum overhead.<\/td>\n<td style=\"width: 33.3333%;\">Requires extra care when writing tests (e.g. check for null pointers).<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 33.3333%;\">Test ends via setjmp()<\/td>\n<td style=\"width: 33.3333%;\">No need to handle &#8216;failed&#8217; case. A failed assertion will automatically abort the rest of the test.<\/td>\n<td style=\"width: 33.3333%;\">Any allocated memory will leak until the end of test session.<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 33.3333%;\">Test ends via C++ exceptions<\/td>\n<td style=\"width: 33.3333%;\">Resources allocated via RAII will get freed when aborting the test (i.e. C++ destructors will get called).<\/td>\n<td style=\"width: 33.3333%;\">Exception support for embedded projects has a considerable memory footprint.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>You can find various other settings (e.g. whether to redirect <strong>printf()<\/strong> output to the test output window) on the same page of <strong>VisualGDB Project Properties<\/strong>.<\/p>\n<h2><a id=\"attributes\"><\/a>Test Attributes<\/h2>\n<p>TinyEmbeddedTest allows assigning attributes to tests to simplify selecting them programmatically. You can declare test attributes as follows:<\/p>\n<pre class=\"\">TEST_WITH_ATTRIBUTES(TestGroupName, TestName, Attribute1, Attribute2, ...)<\/pre>\n<p>In order for test attributes to be discovered correctly, each attribute must be a valid C++ class name (it doesn&#8217;t need to have a definition), e.g.<\/p>\n<pre class=\"\">class MyTestAttribute;\r\n\r\nTEST_WITH_ATTRIBUTES(DemoTestGroup, SuccessfulTest, MyTestAttribute)\r\n{\r\n    printf(\"Hello from test #1\\n\");\r\n}<\/pre>\n<p>You can then run all tests with the <strong>MyTestAttribute<\/strong> attribute using the following command line:<\/p>\n<pre class=\"\">VisualGDB.exe \/runtests &lt;container file&gt; \/attrregex:MyTestAttribute<\/pre>\n<h2>Checking for Memory Leaks<\/h2>\n<p>You can use the <strong>CHECK_FOR_MEMORY_LEAKS()<\/strong> macro at the beginning of the test to automatically fail it if any of the memory allocated during the test was not freed:<\/p>\n<pre class=\"\">TEST(DemoTestGroup, MemoryLeakTest)\r\n{\r\n\tCHECK_FOR_MEMORY_LEAKS();\r\n\tvoid *p = malloc(123);\r\n}<\/pre>\n<p>This can also be done for individual blocks:<\/p>\n<pre class=\"\">TEST(DemoTestGroup, MemoryLeakTest)\r\n{\r\n    InitializeSomething();\r\n\r\n    {\r\n        CHECK_FOR_MEMORY_LEAKS_NAMED(\"First block\");\r\n        void *p = malloc(123);\r\n        free(p);\r\n    }\r\n\r\n    {\r\n        CHECK_FOR_MEMORY_LEAKS_NAMED(\"Second block\");\r\n        void *p = malloc(123);\r\n    }\r\n}<\/pre>\n<h2>Troubleshooting Common Problems<\/h2>\n<p>This section outlines common problems that occur in TinyEmbeddedTest-based projects and describes workarounds for them.<\/p>\n<h3>Multiple definition of _write<\/h3>\n<p>This error would happen if you simultaneously enable the <strong>&#8220;Redirect printf() to Test Output window&#8221;<\/strong> option in TinyEmbeddedTest and one of the following options:<\/p>\n<ul>\n<li><strong>&#8220;Redirect printf() to fast semihosting&#8221;<\/strong> in the <strong>Fast Semihosting and Profiler<\/strong> framework settings.<\/li>\n<li><strong>&#8220;Implementations for _sbrk(), etc.&#8221;<\/strong> =&gt; <strong>&#8220;Support semihosting&#8221; <\/strong>in device\/toolchain settings.<\/li>\n<\/ul>\n<p>It can also happen if your device (e.g. Nordic nRF5x) provides its own implementation of the <strong>_write()<\/strong> function. In either case, removing the other implementations of <strong>_write()<\/strong>, either by disabling the related settings, or by setting the &#8220;excluded from build&#8221; flag on the file providing them, will resolve the problem.<\/p>\n<h3>Tests not running for a newly created project<\/h3>\n<p>If you have created a TinyEmbeddedTest-based project manually, make sure you call <strong>RunAllTests()<\/strong> from <strong>main()<\/strong>. See our <a href=\"https:\/\/visualgdb.com\/tutorials\/tests\/arm\/\">Unit Testing tutorial<\/a> for more details.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This page provides a quick overview of the TinyEmbeddedTest framework. The framework follows the same design principles as the CppUTest<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[217],"tags":[129],"_links":{"self":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/6448"}],"collection":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/comments?post=6448"}],"version-history":[{"count":7,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/6448\/revisions"}],"predecessor-version":[{"id":6629,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/6448\/revisions\/6629"}],"wp:attachment":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/media?parent=6448"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/categories?post=6448"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/tags?post=6448"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}