Sunday, March 9, 2014

Cmock and Unity - Test Framework

Cmock and Unity

Unity - a unit test framework


Unity
•What is Unity?
–Unity is a unit test framework written entirely in the C language.
–Possesses special features for embedded systems
–can be used for any C project.
–only one source file and a couple of header files
–It uses cross-platform Ruby for all the optional add-on scripts.
•src –This is where Unityheader and source file exists
•auto –This contains a collection of Ruby scripts which helps in using unity
–eg. generate_test_runner.rb
-This script will allows to specify any test file name in project and will automatically create a test runner (which includes “main”) to run that test

Unity Test API

RUN_TEST(func)-Each Test is run within the macro RUN_TEST.Thismacro performs necessary setup before thetest is called .
TEST_IGNORE()-Ignore this test and return immediately
TEST_IGNORE_MESSAGE (message)-Ignore this test and return immediately. Output amessage stating why the test was ignored.

Unity Assertion Summary

TEST_ASSERT_TRUE(condition)-Evaluates whatever code is in condition and failsif it evaluates to false
TEST_ASSERT_FALSE(condition)-Evaluates whatever code is in condition and fails
if it evaluates to true
TEST_ASSERT(condition )-Another way of calling TEST_ASSERT_TRUE
TEST_ASSERT_UNLESS(condition)-Another way of calling TEST_ASSERT_FALSE
TEST_FAIL(message)-This test is automatically marked as a failure. The
message is output stating why.

Numerical Assertions:


TEST_ASSERT_EQUAL(expected, actual)-Another way of callingTEST_ASSERT_EQUAL_INT
TEST_ASSERT_EQUAL_INT(expected, actual)-Compare two integers for equality and display
errors as signed integers.
TEST_ASSERT_EQUAL_HEX8(expected, actual)-Compare two integers for equality and display
errors as an 8-bit hex value
TEST_ASSERT_EQUAL_INT_ARRAY(mask, expected, num_elem, actual)-compares 'num_elem' elements of the integer arrays and reports if there are any differences.
TEST_ASSERT_BITS(mask, expected, actual)-Use an integer mask to specify which bits should
be compared between two other integers. High bits in the mask are compared, low bits ignored.
TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual)-Asserts that the actual value is within plus or
minus delta of the expected value.
TEST_ASSERT_EQUAL_STRING(expected, actual)-Compare two null-terminate strings. Fail if any
character is different or if the lengths are different.

How To Use Unity
•Assume a C source file
unity_example.c
#include"unity_example.h"
int sum(int a, int b){
return a + b;
}
int multiply(int x, int y){
return x*y;
}
And......
unity_example.h
int sum(int, int);
int multiply(int, int);
8
Create example test as below.....
unity_example_test.c
#include"unity_example.h"
#include "Unity.h"
void setUp(void)
{
}
void tearDown(void)
{
}
void test_sum(void){
TEST_ASSERT_EQUAL_INT(0, sum(0, 0));
TEST_ASSERT_EQUAL_INT(5, sum(5, 0));
TEST_ASSERT_EQUAL_INT(10, sum(5, 5));
}
void test_multiply(void){
TEST_ASSERT_EQUAL_INT(0, multiply(0, 0));
TEST_ASSERT_EQUAL_INT(0, multiply(5, 0));
TEST_ASSERT_EQUAL_INT(25, multiply(5, 5));
}

Note:
-setup() function is called at
the start of each test function.
-teardown() function is called at
end of each test function.

Create test runner
Create Test runner using generarte_test_runner.rb in auto directory of unity

Generated runner
Generated runner look like this (it includes "main" having all the tests)
unity_example_test_Runner.c
/* AUTOGENERATED FILE. DO NOT EDIT. */
#include "unity.h"
#include
#include
char MessageBuffer[50];
extern void setUp(void);
extern void tearDown(void);
extern void test_sum(void);
extern void test_multiply(void);
11
static void runTest(UnityTestFunction test)
{
if (TEST_PROTECT())
{
setUp();
test();
}
if (TEST_PROTECT())
{
tearDown();
}
}
void resetTest()
{
tearDown();
setUp();
}
int main(void)
{
Unity.TestFile = "unity_example_test.c";
UnityBegin();
// RUN_TEST calls runTest
RUN_TEST(test_sum);
RUN_TEST(test_multiply);
UnityEnd();
getch();
return 0;
}


Running generated test runnner
The generated test runner are build and run to perform the test.
Result of the test :

Cmock-a mocking framework

CMOCK -module/object mocking framework for C projects
What is Cmock ?
–takes header files and creates a Mock interface for it so that you can
more easily Unit test modules that touch other modules.
–uses Ruby to auto-generate C source code mock object modules conforming to the interfaces specified in C header files.
How it works ?
–searches header files for function declarations
eg. int sum(int, int); (in header file CmockTry.h)
-creates a set of Mock objects and helpers
eg. void sum_ExpectAndReturn(int cmock_arg1,
int cmock_arg2, int toReturn);
in file:-
MockCmockTry.h
MockCmockTry.c
-mock are generated using command
ruby cmock.rb CmockTry.h

Write a test ...
CmockTryTest.c
#include"CmockTry.h"
#include"unity.h"
#include"MockCmockTry.h"
void setUp(void)
{
}
void tearDown(void)
{
}
void test_sum(void){
sum_ExpectAndReturn(5, 5, 10);
TEST_ASSERT_EQUAL(10, sum(5, 5));
sum_ExpectAndReturn(1, 1, 2);
TEST_ASSERT_EQUAL(2, sum(1, 1));
}


•Create a test runner using generate_test_runner.rb file in auto directory
ruby generate_test_runner.rb CmockTryTest.c

Generated Mock Module

void func(void)-------void func_Expect(void)
void func(params)--------void func_Expect(expected_params)
retvalfunc(void)------------void func_ExpectAndReturn(retval_to_return)
retvalfunc(params)----------void func_ExpectAndReturn(expected_params, retval_to_return)

Expect:
Note: The expect functions are always generated. The other functions are only generated if those plugins are enabled:

Generated Mock Module

Original Function Generated Mock Function
void func(void)---(nothing. In fact, an additional function is only generated if the paramslist contains pointers)
void func(ptr* param, other)----void func_ExpectWithArray(ptr* param, intparam_depth, other)
retvalfunc(void)---(nothing. In fact, an additional function is only generated if the paramslist contains pointers)
retvalfunc(other, ptr* param)---void func_ExpectWithArrayAndReturn(other, ptr* param, intparam_depth, retval_to_return)

Array:
Note: An ExpectWithArray will check as many elements as you specify. If you specify zero elements, it will check just the pointer if :smart mode is configured or fail if :compare_data is set.
19
Mocking from the Command Line
Example:
•this will create mocks using the configuration specified in MyConfig.yml:
ruby cmock.rb -oMyConfig.yml super.h duper.h awesome.h
•this will create mocks using the default configuration:
ruby cmock.rb ../mocking/stuff/is/fun.h ../try/it/yourself.h
•inject options directly to the command
ruby cmock.rb --mock_path=”build/mocks” blah.h

Mocking From Scripts or Rake
•default settings:
cmock = CMock.new
•Specify a YAML file containing the configuration options you desire:
cmock = CMock.new('../MyConfig.yml')
•Specify the options explicitly:
cmock = Cmock.new(:plugins => [:cexception, :ignore], :mock_path => 'my/mocks/')