Unit Testing framework based on http://cpputest.github.io/

CppUTest

Where to find more information

Getting test reports on the console

You may need to tailor the file src/Platforms/mbed/UtestPlatform.cpp to your needs. In particular, if you want console output, you might want to look at the function PlatformSpecificPutchar().

Quick introduction (some code!)

To write your first test, all you need is a new cpp file with a TEST_GROUP and a TEST, like:

#include "CppUTest/TestHarness.h"

TEST_GROUP(FirstTestGroup)
{
};

TEST(FirstTestGroup, FirstTest)
{
   FAIL("Fail me!");
}

This test will fail.

You can add new tests to the test group by just writing more tests in the file, like this:

TEST(FirstTestGroup, SecondTest)
{
   STRCMP_EQUAL("hello", "world");
   LONGS_EQUAL(1, 2);
   CHECK(false);
}

You do need to trigger the tests from somewhere in your program. It could look something like:

#include "CppUTest/TestRegistry.h"
#include "CppUTest/CommandLineTestRunner.h"

int main(int ac, char** av)
{
    ....
    unsigned failureCount = 0;
    {
        ConsoleTestOutput output;
        CommandLineTestRunner runner(ac, av, &output, TestRegistry::getCurrentRegistry());
        failureCount = runner.runAllTestsMain();
    }

    if (failureCount == 0) {
        console.printf("PASSED\r\n");
    }
    ...
}

For more information, We’d recommend to read the manual or, even better, check some existing tests such as SimpleStringTest or (a bit more complicated) MemoryLeakDetectorTest or the mocking tests or just check out the Cheat Sheet.

Committer:
rgrover1
Date:
Tue Jan 28 09:27:41 2014 +0000
Revision:
0:0b799af9d58e
Child:
1:4769360130ed
CppUTest unit test framework.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rgrover1 0:0b799af9d58e 1 /*
rgrover1 0:0b799af9d58e 2 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
rgrover1 0:0b799af9d58e 3 * All rights reserved.
rgrover1 0:0b799af9d58e 4 *
rgrover1 0:0b799af9d58e 5 * Redistribution and use in source and binary forms, with or without
rgrover1 0:0b799af9d58e 6 * modification, are permitted provided that the following conditions are met:
rgrover1 0:0b799af9d58e 7 * * Redistributions of source code must retain the above copyright
rgrover1 0:0b799af9d58e 8 * notice, this list of conditions and the following disclaimer.
rgrover1 0:0b799af9d58e 9 * * Redistributions in binary form must reproduce the above copyright
rgrover1 0:0b799af9d58e 10 * notice, this list of conditions and the following disclaimer in the
rgrover1 0:0b799af9d58e 11 * documentation and/or other materials provided with the distribution.
rgrover1 0:0b799af9d58e 12 * * Neither the name of the <organization> nor the
rgrover1 0:0b799af9d58e 13 * names of its contributors may be used to endorse or promote products
rgrover1 0:0b799af9d58e 14 * derived from this software without specific prior written permission.
rgrover1 0:0b799af9d58e 15 *
rgrover1 0:0b799af9d58e 16 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
rgrover1 0:0b799af9d58e 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
rgrover1 0:0b799af9d58e 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
rgrover1 0:0b799af9d58e 19 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
rgrover1 0:0b799af9d58e 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
rgrover1 0:0b799af9d58e 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
rgrover1 0:0b799af9d58e 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
rgrover1 0:0b799af9d58e 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
rgrover1 0:0b799af9d58e 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
rgrover1 0:0b799af9d58e 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
rgrover1 0:0b799af9d58e 26 */
rgrover1 0:0b799af9d58e 27
rgrover1 0:0b799af9d58e 28 #include "CppUTest/TestHarness.h"
rgrover1 0:0b799af9d58e 29 #include "CppUTest/JUnitTestOutput.h"
rgrover1 0:0b799af9d58e 30 #include "CppUTest/TestResult.h"
rgrover1 0:0b799af9d58e 31 #include "CppUTest/TestFailure.h"
rgrover1 0:0b799af9d58e 32 #include "CppUTest/PlatformSpecificFunctions.h"
rgrover1 0:0b799af9d58e 33
rgrover1 0:0b799af9d58e 34 struct JUnitTestCaseResultNode
rgrover1 0:0b799af9d58e 35 {
rgrover1 0:0b799af9d58e 36 JUnitTestCaseResultNode() :
rgrover1 0:0b799af9d58e 37 execTime_(0), failure_(0), next_(0)
rgrover1 0:0b799af9d58e 38 {
rgrover1 0:0b799af9d58e 39 }
rgrover1 0:0b799af9d58e 40
rgrover1 0:0b799af9d58e 41 SimpleString name_;
rgrover1 0:0b799af9d58e 42 long execTime_;
rgrover1 0:0b799af9d58e 43 TestFailure* failure_;
rgrover1 0:0b799af9d58e 44 JUnitTestCaseResultNode* next_;
rgrover1 0:0b799af9d58e 45 };
rgrover1 0:0b799af9d58e 46
rgrover1 0:0b799af9d58e 47 struct JUnitTestGroupResult
rgrover1 0:0b799af9d58e 48 {
rgrover1 0:0b799af9d58e 49 JUnitTestGroupResult() :
rgrover1 0:0b799af9d58e 50 testCount_(0), failureCount_(0), startTime_(0), groupExecTime_(0), head_(0), tail_(0)
rgrover1 0:0b799af9d58e 51 {
rgrover1 0:0b799af9d58e 52 }
rgrover1 0:0b799af9d58e 53
rgrover1 0:0b799af9d58e 54 int testCount_;
rgrover1 0:0b799af9d58e 55 int failureCount_;
rgrover1 0:0b799af9d58e 56 long startTime_;
rgrover1 0:0b799af9d58e 57 long groupExecTime_;
rgrover1 0:0b799af9d58e 58 SimpleString group_;
rgrover1 0:0b799af9d58e 59 JUnitTestCaseResultNode* head_;
rgrover1 0:0b799af9d58e 60 JUnitTestCaseResultNode* tail_;
rgrover1 0:0b799af9d58e 61 };
rgrover1 0:0b799af9d58e 62
rgrover1 0:0b799af9d58e 63 struct JUnitTestOutputImpl
rgrover1 0:0b799af9d58e 64 {
rgrover1 0:0b799af9d58e 65 JUnitTestGroupResult results_;
rgrover1 0:0b799af9d58e 66 PlatformSpecificFile file_;
rgrover1 0:0b799af9d58e 67 };
rgrover1 0:0b799af9d58e 68
rgrover1 0:0b799af9d58e 69 JUnitTestOutput::JUnitTestOutput() :
rgrover1 0:0b799af9d58e 70 impl_(new JUnitTestOutputImpl)
rgrover1 0:0b799af9d58e 71 {
rgrover1 0:0b799af9d58e 72 }
rgrover1 0:0b799af9d58e 73
rgrover1 0:0b799af9d58e 74 JUnitTestOutput::~JUnitTestOutput()
rgrover1 0:0b799af9d58e 75 {
rgrover1 0:0b799af9d58e 76 resetTestGroupResult();
rgrover1 0:0b799af9d58e 77 delete impl_;
rgrover1 0:0b799af9d58e 78 }
rgrover1 0:0b799af9d58e 79
rgrover1 0:0b799af9d58e 80 void JUnitTestOutput::resetTestGroupResult()
rgrover1 0:0b799af9d58e 81 {
rgrover1 0:0b799af9d58e 82 impl_->results_.testCount_ = 0;
rgrover1 0:0b799af9d58e 83 impl_->results_.failureCount_ = 0;
rgrover1 0:0b799af9d58e 84 impl_->results_.group_ = "";
rgrover1 0:0b799af9d58e 85 JUnitTestCaseResultNode* cur = impl_->results_.head_;
rgrover1 0:0b799af9d58e 86 while (cur) {
rgrover1 0:0b799af9d58e 87 JUnitTestCaseResultNode* tmp = cur->next_;
rgrover1 0:0b799af9d58e 88 ;
rgrover1 0:0b799af9d58e 89 if (cur->failure_) delete cur->failure_;
rgrover1 0:0b799af9d58e 90 delete cur;
rgrover1 0:0b799af9d58e 91 cur = tmp;
rgrover1 0:0b799af9d58e 92 }
rgrover1 0:0b799af9d58e 93 impl_->results_.head_ = 0;
rgrover1 0:0b799af9d58e 94 impl_->results_.tail_ = 0;
rgrover1 0:0b799af9d58e 95 }
rgrover1 0:0b799af9d58e 96
rgrover1 0:0b799af9d58e 97 void JUnitTestOutput::printTestsStarted()
rgrover1 0:0b799af9d58e 98 {
rgrover1 0:0b799af9d58e 99 }
rgrover1 0:0b799af9d58e 100
rgrover1 0:0b799af9d58e 101 void JUnitTestOutput::printCurrentGroupStarted(const UtestShell& /*test*/)
rgrover1 0:0b799af9d58e 102 {
rgrover1 0:0b799af9d58e 103 }
rgrover1 0:0b799af9d58e 104
rgrover1 0:0b799af9d58e 105 void JUnitTestOutput::printCurrentTestEnded(const TestResult& result)
rgrover1 0:0b799af9d58e 106 {
rgrover1 0:0b799af9d58e 107 impl_->results_.tail_->execTime_
rgrover1 0:0b799af9d58e 108 = result.getCurrentTestTotalExecutionTime();
rgrover1 0:0b799af9d58e 109 }
rgrover1 0:0b799af9d58e 110
rgrover1 0:0b799af9d58e 111 void JUnitTestOutput::printTestsEnded(const TestResult& /*result*/)
rgrover1 0:0b799af9d58e 112 {
rgrover1 0:0b799af9d58e 113 }
rgrover1 0:0b799af9d58e 114
rgrover1 0:0b799af9d58e 115 void JUnitTestOutput::printCurrentGroupEnded(const TestResult& result)
rgrover1 0:0b799af9d58e 116 {
rgrover1 0:0b799af9d58e 117 impl_->results_.groupExecTime_ = result.getCurrentGroupTotalExecutionTime();
rgrover1 0:0b799af9d58e 118 writeTestGroupToFile();
rgrover1 0:0b799af9d58e 119 resetTestGroupResult();
rgrover1 0:0b799af9d58e 120 }
rgrover1 0:0b799af9d58e 121
rgrover1 0:0b799af9d58e 122 void JUnitTestOutput::printCurrentTestStarted(const UtestShell& test)
rgrover1 0:0b799af9d58e 123 {
rgrover1 0:0b799af9d58e 124 impl_->results_.testCount_++;
rgrover1 0:0b799af9d58e 125 impl_->results_.group_ = test.getGroup();
rgrover1 0:0b799af9d58e 126 impl_->results_.startTime_ = GetPlatformSpecificTimeInMillis();
rgrover1 0:0b799af9d58e 127
rgrover1 0:0b799af9d58e 128 if (impl_->results_.tail_ == 0) {
rgrover1 0:0b799af9d58e 129 impl_->results_.head_ = impl_->results_.tail_
rgrover1 0:0b799af9d58e 130 = new JUnitTestCaseResultNode;
rgrover1 0:0b799af9d58e 131 }
rgrover1 0:0b799af9d58e 132 else {
rgrover1 0:0b799af9d58e 133 impl_->results_.tail_->next_ = new JUnitTestCaseResultNode;
rgrover1 0:0b799af9d58e 134 impl_->results_.tail_ = impl_->results_.tail_->next_;
rgrover1 0:0b799af9d58e 135 }
rgrover1 0:0b799af9d58e 136 impl_->results_.tail_->name_ = test.getName();
rgrover1 0:0b799af9d58e 137 }
rgrover1 0:0b799af9d58e 138
rgrover1 0:0b799af9d58e 139 SimpleString JUnitTestOutput::createFileName(const SimpleString& group)
rgrover1 0:0b799af9d58e 140 {
rgrover1 0:0b799af9d58e 141 SimpleString fileName = "cpputest_";
rgrover1 0:0b799af9d58e 142 fileName += group;
rgrover1 0:0b799af9d58e 143 fileName.replace('/', '_');
rgrover1 0:0b799af9d58e 144 fileName += ".xml";
rgrover1 0:0b799af9d58e 145 return fileName;
rgrover1 0:0b799af9d58e 146 }
rgrover1 0:0b799af9d58e 147
rgrover1 0:0b799af9d58e 148 void JUnitTestOutput::writeXmlHeader()
rgrover1 0:0b799af9d58e 149 {
rgrover1 0:0b799af9d58e 150 writeToFile("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
rgrover1 0:0b799af9d58e 151 }
rgrover1 0:0b799af9d58e 152
rgrover1 0:0b799af9d58e 153 void JUnitTestOutput::writeTestSuiteSummery()
rgrover1 0:0b799af9d58e 154 {
rgrover1 0:0b799af9d58e 155 SimpleString
rgrover1 0:0b799af9d58e 156 buf =
rgrover1 0:0b799af9d58e 157 StringFromFormat(
rgrover1 0:0b799af9d58e 158 "<testsuite errors=\"0\" failures=\"%d\" hostname=\"localhost\" name=\"%s\" tests=\"%d\" time=\"%d.%03d\" timestamp=\"%s\">\n",
rgrover1 0:0b799af9d58e 159 impl_->results_.failureCount_,
rgrover1 0:0b799af9d58e 160 impl_->results_.group_.asCharString(),
rgrover1 0:0b799af9d58e 161 impl_->results_.testCount_,
rgrover1 0:0b799af9d58e 162 (int) (impl_->results_.groupExecTime_ / 1000), (int) (impl_->results_.groupExecTime_ % 1000),
rgrover1 0:0b799af9d58e 163 GetPlatformSpecificTimeString());
rgrover1 0:0b799af9d58e 164 writeToFile(buf.asCharString());
rgrover1 0:0b799af9d58e 165 }
rgrover1 0:0b799af9d58e 166
rgrover1 0:0b799af9d58e 167 void JUnitTestOutput::writeProperties()
rgrover1 0:0b799af9d58e 168 {
rgrover1 0:0b799af9d58e 169 writeToFile("<properties>\n");
rgrover1 0:0b799af9d58e 170 writeToFile("</properties>\n");
rgrover1 0:0b799af9d58e 171 }
rgrover1 0:0b799af9d58e 172
rgrover1 0:0b799af9d58e 173 void JUnitTestOutput::writeTestCases()
rgrover1 0:0b799af9d58e 174 {
rgrover1 0:0b799af9d58e 175 JUnitTestCaseResultNode* cur = impl_->results_.head_;
rgrover1 0:0b799af9d58e 176 while (cur) {
rgrover1 0:0b799af9d58e 177 SimpleString buf = StringFromFormat(
rgrover1 0:0b799af9d58e 178 "<testcase classname=\"%s\" name=\"%s\" time=\"%d.%03d\">\n",
rgrover1 0:0b799af9d58e 179 impl_->results_.group_.asCharString(),
rgrover1 0:0b799af9d58e 180 cur->name_.asCharString(), (int) (cur->execTime_ / 1000), (int)(cur->execTime_ % 1000));
rgrover1 0:0b799af9d58e 181 writeToFile(buf.asCharString());
rgrover1 0:0b799af9d58e 182
rgrover1 0:0b799af9d58e 183 if (cur->failure_) {
rgrover1 0:0b799af9d58e 184 writeFailure(cur);
rgrover1 0:0b799af9d58e 185 }
rgrover1 0:0b799af9d58e 186 writeToFile("</testcase>\n");
rgrover1 0:0b799af9d58e 187 cur = cur->next_;
rgrover1 0:0b799af9d58e 188 }
rgrover1 0:0b799af9d58e 189 }
rgrover1 0:0b799af9d58e 190
rgrover1 0:0b799af9d58e 191 void JUnitTestOutput::writeFailure(JUnitTestCaseResultNode* node)
rgrover1 0:0b799af9d58e 192 {
rgrover1 0:0b799af9d58e 193 SimpleString message = node->failure_->getMessage().asCharString();
rgrover1 0:0b799af9d58e 194 message.replace('"', '\'');
rgrover1 0:0b799af9d58e 195 message.replace('<', '[');
rgrover1 0:0b799af9d58e 196 message.replace('>', ']');
rgrover1 0:0b799af9d58e 197 message.replace("&", "&amp;");
rgrover1 0:0b799af9d58e 198 message.replace("\n", "{newline}");
rgrover1 0:0b799af9d58e 199 SimpleString buf = StringFromFormat(
rgrover1 0:0b799af9d58e 200 "<failure message=\"%s:%d: %s\" type=\"AssertionFailedError\">\n",
rgrover1 0:0b799af9d58e 201 node->failure_->getFileName().asCharString(),
rgrover1 0:0b799af9d58e 202 node->failure_->getFailureLineNumber(), message.asCharString());
rgrover1 0:0b799af9d58e 203 writeToFile(buf.asCharString());
rgrover1 0:0b799af9d58e 204 writeToFile("</failure>\n");
rgrover1 0:0b799af9d58e 205 }
rgrover1 0:0b799af9d58e 206
rgrover1 0:0b799af9d58e 207 void JUnitTestOutput::writeFileEnding()
rgrover1 0:0b799af9d58e 208 {
rgrover1 0:0b799af9d58e 209 writeToFile("<system-out></system-out>\n");
rgrover1 0:0b799af9d58e 210 writeToFile("<system-err></system-err>\n");
rgrover1 0:0b799af9d58e 211 writeToFile("</testsuite>");
rgrover1 0:0b799af9d58e 212 }
rgrover1 0:0b799af9d58e 213
rgrover1 0:0b799af9d58e 214 void JUnitTestOutput::writeTestGroupToFile()
rgrover1 0:0b799af9d58e 215 {
rgrover1 0:0b799af9d58e 216 openFileForWrite(createFileName(impl_->results_.group_));
rgrover1 0:0b799af9d58e 217 writeXmlHeader();
rgrover1 0:0b799af9d58e 218 writeTestSuiteSummery();
rgrover1 0:0b799af9d58e 219 writeProperties();
rgrover1 0:0b799af9d58e 220 writeTestCases();
rgrover1 0:0b799af9d58e 221 writeFileEnding();
rgrover1 0:0b799af9d58e 222 closeFile();
rgrover1 0:0b799af9d58e 223 }
rgrover1 0:0b799af9d58e 224
rgrover1 0:0b799af9d58e 225 void JUnitTestOutput::verbose()
rgrover1 0:0b799af9d58e 226 {
rgrover1 0:0b799af9d58e 227 }
rgrover1 0:0b799af9d58e 228
rgrover1 0:0b799af9d58e 229 void JUnitTestOutput::printBuffer(const char*)
rgrover1 0:0b799af9d58e 230 {
rgrover1 0:0b799af9d58e 231 }
rgrover1 0:0b799af9d58e 232
rgrover1 0:0b799af9d58e 233 void JUnitTestOutput::print(const char*)
rgrover1 0:0b799af9d58e 234 {
rgrover1 0:0b799af9d58e 235 }
rgrover1 0:0b799af9d58e 236
rgrover1 0:0b799af9d58e 237 void JUnitTestOutput::print(long)
rgrover1 0:0b799af9d58e 238 {
rgrover1 0:0b799af9d58e 239 }
rgrover1 0:0b799af9d58e 240
rgrover1 0:0b799af9d58e 241 void JUnitTestOutput::print(const TestFailure& failure)
rgrover1 0:0b799af9d58e 242 {
rgrover1 0:0b799af9d58e 243 if (impl_->results_.tail_->failure_ == 0) {
rgrover1 0:0b799af9d58e 244 impl_->results_.failureCount_++;
rgrover1 0:0b799af9d58e 245 impl_->results_.tail_->failure_ = new TestFailure(failure);
rgrover1 0:0b799af9d58e 246 }
rgrover1 0:0b799af9d58e 247 }
rgrover1 0:0b799af9d58e 248
rgrover1 0:0b799af9d58e 249 void JUnitTestOutput::printTestRun(int /*number*/, int /*total*/)
rgrover1 0:0b799af9d58e 250 {
rgrover1 0:0b799af9d58e 251 }
rgrover1 0:0b799af9d58e 252
rgrover1 0:0b799af9d58e 253 void JUnitTestOutput::flush()
rgrover1 0:0b799af9d58e 254 {
rgrover1 0:0b799af9d58e 255 }
rgrover1 0:0b799af9d58e 256
rgrover1 0:0b799af9d58e 257 void JUnitTestOutput::openFileForWrite(const SimpleString& fileName)
rgrover1 0:0b799af9d58e 258 {
rgrover1 0:0b799af9d58e 259 impl_->file_ = PlatformSpecificFOpen(fileName.asCharString(), "w");
rgrover1 0:0b799af9d58e 260 }
rgrover1 0:0b799af9d58e 261
rgrover1 0:0b799af9d58e 262 void JUnitTestOutput::writeToFile(const SimpleString& buffer)
rgrover1 0:0b799af9d58e 263 {
rgrover1 0:0b799af9d58e 264 PlatformSpecificFPuts(buffer.asCharString(), impl_->file_);
rgrover1 0:0b799af9d58e 265 }
rgrover1 0:0b799af9d58e 266
rgrover1 0:0b799af9d58e 267 void JUnitTestOutput::closeFile()
rgrover1 0:0b799af9d58e 268 {
rgrover1 0:0b799af9d58e 269 PlatformSpecificFClose(impl_->file_);
rgrover1 0:0b799af9d58e 270 }