1. 程式人生 > >work with ceedling

work with ceedling

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:

Welcome 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
2. go to the folder of MyTest and crate new moduel - tempSensor
ceeding module:create[tempSensor]

new file generated as follows:

Cools! Let's add the first test there:

in test_tempSensor.c

void 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);
}
Then we'll do somthing different, to follow the principle on TDD
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;
}