work with ceedling
阿新 • • 發佈:2018-12-04
References:
http://www.electronvector.com/blog/mocking-embedded-hardware-interfaces-with-ceedling-and-cmock
1. Generate new project MyTest
ceedling new MyTest
The output will be something like this:
2. go to the folder of MyTest and crate new moduel - tempSensorWelcome to Ceedling! create MyTest/vendor/ceedling/docs/CeedlingPacket.md create MyTest/vendor/ceedling/docs/CException.md create MyTest/vendor/ceedling/docs/CMock_Summary.md create MyTest/vendor/ceedling/docs/UnityAssertionsCheatSheetSuitableforPrintingandPossiblyFraming.pdf create MyTest/vendor/ceedling/docs/UnityAssertionsReference.md ...... create MyTest/vendor/ceedling/vendor/unity/release create MyTest/vendor/ceedling/vendor/unity/release/build.info create MyTest/vendor/ceedling/vendor/unity/release/version.info create MyTest/vendor/ceedling/vendor/unity/src create MyTest/vendor/ceedling/vendor/unity/src/unity.c create MyTest/vendor/ceedling/vendor/unity/src/unity.h create MyTest/vendor/ceedling/vendor/unity/src/unity_internals.h create MyTest/project.yml Project 'MyTest' created! - Tool documentation is located in vendor/ceedling/docs - Execute 'ceedling help' to view available test & build tasks
ceeding module:create[tempSensor]
new file generated as follows:
Cools! Let's add the first test there:
in test_tempSensor.c
Then we'll do somthing different, to follow the principle on TDDvoid test_whenTempRegisterReadsMaxValue_thenTheTempIsTheMaxValue(void) { uint8_t tempRegisterAddress = 0x03; float expectedTemperature = 104.6f; float tolerance = 0.1f; //When i2c_readRegister_ExpectAndReturn(tempRegisterAddress, 0x3ff); //Then float actualTemperature = tempSensor_getTemperature(); TEST_ASSERT_FLOAT_WITHIN(tolerance, expectedTemperature, actualTemperature); }
ceedling test:all
As we expected, it failed:
Test 'test_tempSensor.c' ------------------------ Generating runner for test_tempSensor.c... Compiling test_tempSensor_runner.c... Compiling test_tempSensor.c... test/test_tempSensor.c: In function ‘test_whenTempRegisterReadsMaxValue_thenTheTempIsTheMaxValue’: test/test_tempSensor.c:24:5: warning: implicit declaration of function ‘i2c_readRegister_ExpectAndReturn’ [-Wimplicit-function-declaration] i2c_readRegister_ExpectAndReturn(tempRegisterAddress, 0x3ff); ^ test/test_tempSensor.c:27:31: warning: implicit declaration of function ‘tempSensor_getTemperature’ [-Wimplicit-function-declaration] float actualTemperature = tempSensor_getTemperature(); ^ Compiling unity.c... Compiling tempSensor.c... Compiling cmock.c... Linking test_tempSensor.out... build/test/out/test_tempSensor.o: In function `test_whenTempRegisterReadsMaxValue_thenTheTempIsTheMaxValue': ./MyTest/test/test_tempSensor.c:24: undefined reference to `i2c_readRegister_ExpectAndReturn' ./MyTest/test/test_tempSensor.c:27: undefined reference to `tempSensor_getTemperature' collect2: error: ld returned 1 exit status
Add declaration and defintion for tempSensor_getTemperature
tempSensor.h:
# ifndef tempSensor_H
# define tempSensor_H
float tempSensor_getTemperature(void);
# endif // tempSensor_H
tempSensor.c:
# include "tempSensor.h"
float tempSensor_getTemperature(void)
{
return 0.0f;
}
There's the mock function
i2c_readReadgister_ExpectAndReturn.
Let's add it automatically. create file "i2c.h", and include the mock header file into test_tempSensor.c.
#include "mock_i2c.h"
Run test again: ceedling test:all. And very perfect to see mock_i2c.c created and test failure.
Test 'test_tempSensor.c'
------------------------
Creating mock for i2c...
Generating runner for test_tempSensor.c...
Compiling test_tempSensor_runner.c...
Compiling test_tempSensor.c...
Compiling mock_i2c.c...
Compiling tempSensor.c...
Linking test_tempSensor.out...
Running test_tempSensor.out...
--------------------
IGNORED TEST SUMMARY
--------------------
[test_tempSensor.c]
Test: test_tempSensor_NeedToImplement
At line (15): "Need to Implement tempSensor"
-------------------
FAILED TEST SUMMARY
-------------------
[test_tempSensor.c]
Test: test_whenTempRegisterReadsMaxValue_thenTheTempIsTheMaxValue
At line (30): "Expected 104.6 Was 0"
--------------------
OVERALL TEST SUMMARY
--------------------
TESTED: 2
PASSED: 0
FAILED: 1
IGNORED: 1
---------------------
BUILD FAILURE SUMMARY
---------------------
Unit test failures.
Coding to make the test Pass:
float tempSensor_getTemperature(void)
{
unsinged short rawValue = i2c_readRegister(0x03);
return -100.0f + (0.2f * (float)rawValue);
}
Test 'test_tempSensor.c'
------------------------
Compiling tempSensor.c...
src/tempSensor.c: In function ‘tempSensor_getTemperature’:
src/tempSensor.c:5:31: warning: implicit declaration of function ‘i2c_readRegister’ [-Wimplicit-function-declaration]
unsigned short rawValue = i2c_readRegister(0x03);
^
Linking test_tempSensor.out...
Running test_tempSensor.out...
--------------------
IGNORED TEST SUMMARY
--------------------
[test_tempSensor.c]
Test: test_tempSensor_NeedToImplement
At line (15): "Need to Implement tempSensor"
--------------------
OVERALL TEST SUMMARY
--------------------
TESTED: 2
PASSED: 1
FAILED: 0
IGNORED: 1
Amazing that we didn't even do any code for
i2c_readRegister
but it passed.
Let's dig out it in to the mock.
vim ./build/test/mocks/mock_i2c.c
Very complicated than what we can imagine.
uint16_t i2c_readRegister(uint8_t registerAddress)
{
UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;
CMOCK_i2c_readRegister_CALL_INSTANCE* cmock_call_instance;
UNITY_SET_DETAIL(CMockString_i2c_readRegister);
cmock_call_instance = (CMOCK_i2c_readRegister_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.i2c_readRegister_CallInstance);
Mock.i2c_readRegister_CallInstance = CMock_Guts_MemNext(Mock.i2c_readRegister_CallInstance);
if (Mock.i2c_readRegister_IgnoreBool)
{
UNITY_CLR_DETAILS();
if (cmock_call_instance == NULL)
return Mock.i2c_readRegister_FinalReturn;
Mock.i2c_readRegister_FinalReturn = cmock_call_instance->ReturnVal;
return cmock_call_instance->ReturnVal;
}
if (Mock.i2c_readRegister_CallbackFunctionPointer != NULL)
{
return Mock.i2c_readRegister_CallbackFunctionPointer(registerAddress, Mock.i2c_readRegister_CallbackCalls++);
}
UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringCalledMore);
cmock_line = cmock_call_instance->LineNumber;
if (cmock_call_instance->CallOrder > ++GlobalVerifyOrder)
UNITY_TEST_FAIL(cmock_line, CMockStringCalledEarly);
if (cmock_call_instance->CallOrder < GlobalVerifyOrder)
UNITY_TEST_FAIL(cmock_line, CMockStringCalledLate);
{
UNITY_SET_DETAILS(CMockString_i2c_readRegister,CMockString_registerAddress);
UNITY_TEST_ASSERT_EQUAL_HEX8(cmock_call_instance->Expected_registerAddress, registerAddress, cmock_line, CMockStringMismatch);
}
UNITY_CLR_DETAILS();
return cmock_call_instance->ReturnVal;
}