如何为IAR嵌入式工作台项目配置Ceedling?

Tag*_*agc 1 c embedded tdd iar unity-test-framework

我正在尝试为嵌入式应用程序开发一项新功能,并且我想使用测试驱动的方法来进行。

该项目使用纯C语言编写,并且正在使用IAR Embedded Workbench 6.60.1.5104开发。我的目标是LPC1788,这是一种Cortex-M3设备,所有开发工作都是在64位Windows 7计算机上完成的。现在,我更赞成让单元测试在PC上而不是目标硬件上运行(RAM相当有限)。

我遇到了一本关于嵌入式C的测试驱动开发的有用的书,它向我指出了Unity,CppUTest,Ceedling等工具。研究了这些内容之后,我认为我的最佳选择是配置Ceedling(使用Unity )用于我的项目。但是,我不确定要配置Ceedling与我当前的IAR工具链一起使用时需要采取什么步骤。

我已经安装了Ceedling并创建了“ blinky”示例项目,并且尝试使用IAR工具链进行构建和测试。我已添加iccarm.exe到路径并按blinky/project.yml如下所示进行编辑:

---

# Notes:
# This is a fully tested project that demonstrates the use
# of a timer ISR to blink the on board LED of an Arduino UNO
:project:
  :use_exceptions: FALSE
  :use_test_preprocessor: TRUE
  :use_auxiliary_dependencies: TRUE
  :build_root: build
  :release_build: TRUE
  :test_file_prefix: test_

#You'll have to specify these
:environment:
  - :mcu: atmega328p
  - :f_cpu: 16000000UL 
  - :serial_port: COM8  #change this to the serial port you are using!!!
  - :objcopy: avr-objcopy
  # Uncomment these lines if you are using windows and don't have these tools in your path
  # - :path:
    # - C:\mingw\bin
    # - C:\WinAVR-20100110\bin
    # - C:\WinAVR-20100110\utils\bin
    # - #{ENV['PATH']}

:extension:
  :executable: .bin

:release_build:
  :output: blinky

:paths:
  :test:
    - +:test/**
    - -:test/support
  :source:
    - src/**
  :support:
    - test/support

:defines:
  # in order to add common defines:
  #  1) remove the trailing [] from the :common: section
  #  2) add entries to the :common: section (e.g. :test: has TEST defined)
  :commmon: &common_defines []
  :test:
    - *common_defines
    - TEST
  :test_preprocess:
    - *common_defines
    - TEST

:tools:
  :release_compiler:
    :executable: avr-gcc
    :arguments:
      - ${1}
      - -DTARGET
      - -DF_CPU=#{ENV['F_CPU']}
      - -mmcu=#{ENV['MCU']}
      - -Iinclude/
      - -Wall
      - -Os
      - -c
      - -o ${2}
  :release_linker:
    :executable: avr-gcc
    :arguments:
      - -mmcu=#{ENV['MCU']}
      - ${1}
      - -o ${2}.bin

:cmock:
  :mock_prefix: mock_
  :when_no_prototypes: :warn
  :enforce_strict_ordering: TRUE
  :plugins:
    - :ignore
  :treat_as:
    uint8:    HEX8
    uint16:   HEX16
    uint32:   UINT32
    int8:     INT8
    bool:     UINT8

:tools:
  :test_file_preprocessor:
    :executable: iccarm
    :name: 'IAR test file preprocessor'

  :test_includes_preprocessor:
    :executable: iccarm
    :name: 'IAR test includes preprocessor'

  :test_compiler:
    :executable: iccarm
    :name: 'IAR test compiler'

  :test_linker:
    :executable: iccarm
    :name: 'IAR test linker'

  :release_compiler:
    :executable: iccarm
    :name: 'IAR release compiler'

  :release_linker:
    :executable: iccarm
    :name: 'IAR release linker'

:plugins:
  :load_paths:
    - vendor/ceedling/plugins
  :enabled:
    - stdout_pretty_tests_report
    - module_generator
...
Run Code Online (Sandbox Code Playgroud)

这和默认值之间的唯一区别project.yml是第二:tools部分下的内容。

我的猜测是我朝着正确的方向前进,但是我不确定是否iccarm.exe适用于工具链所有这些部分的正确可执行文件以及我需要传递的参数。

如果我可以配置Ceedling以使用IAR工具链来构建和测试眨眼项目,我希望我应该能够对我的实际项目应用相同的配置。如果我rake现在尝试运行,将得到以下输出:

$ rake


Test 'test_BlinkTask.c'
-----------------------
rake aborted!
Errno::ENOENT: No such file or directory @ rb_sysopen - build/test/preprocess/files/test_BlinkTask.c
C:/Users/davidfallah/Documents/IAR Projects/blinky/vendor/ceedling/lib/ceedling/preprocessinator_extractor.rb:18:in `readlines'
C:/Users/davidfallah/Documents/IAR Projects/blinky/vendor/ceedling/lib/ceedling/preprocessinator_extractor.rb:18:in `extract_base_file_from_preprocessed_expansion'
C:/Users/davidfallah/Documents/IAR Projects/blinky/vendor/ceedling/lib/ceedling/preprocessinator_file_handler.rb:14:in `preprocess_file'
C:/Users/davidfallah/Documents/IAR Projects/blinky/vendor/ceedling/lib/ceedling/preprocessinator.rb:40:in `preprocess_file'
C:/Users/davidfallah/Documents/IAR Projects/blinky/vendor/ceedling/lib/ceedling/preprocessinator.rb:12:in `block in setup'
C:/Users/davidfallah/Documents/IAR Projects/blinky/vendor/ceedling/lib/ceedling/preprocessinator_helper.rb:33:in `preprocess_test_file'
C:/Users/davidfallah/Documents/IAR Projects/blinky/vendor/ceedling/lib/ceedling/preprocessinator.rb:25:in `preprocess_test_and_invoke_test_mocks'
C:/Users/davidfallah/Documents/IAR Projects/blinky/vendor/ceedling/lib/ceedling/test_invoker.rb:42:in `block in setup_and_invoke'
C:/Users/davidfallah/Documents/IAR Projects/blinky/vendor/ceedling/lib/ceedling/test_invoker.rb:32:in `setup_and_invoke'
C:/Users/davidfallah/Documents/IAR Projects/blinky/vendor/ceedling/lib/ceedling/tasks_tests.rake:11:in `block (2 levels) in <top (required)>'
Tasks: TOP => default => test:all
(See full trace by running task with --trace)

--------------------
OVERALL TEST SUMMARY
--------------------

No tests executed.
Run Code Online (Sandbox Code Playgroud)

我认为这是因为测试文件预处理器应将测试文件复制到该build/test/preprocess/files目录下,但当前不会发生。

经过一番挖掘后,我发现该示例示例配置文件似乎对您有所帮助。它适用于IAR EW / Cortex M3环境,例如我正在使用的环境。这可能表明我需要在Ceedling中指定哪些配置选项project.yml

如果我可以让Ceedling blinky使用IAR工具链构建和测试项目,那么我希望我可以使其适应于我的实际项目。任何帮助,将不胜感激。

Tag*_*agc 5

这是一个挣扎,但我相信我已经成功配置Ceedling来帮助测试我的项目。希望对希望在IAR项目中使用Ceedling的任何其他人有用。

Ceedling CLI具有命令(ceedling new <proj_name>),可让您使用Ceedling期望的结构创建新项目。您还可以指定现有项目的名称,在这种情况下,它仅添加必要的文件以使其与Ceedling兼容,这就是我对项目所做的事情。

作为参考,执行此步骤后,我的项目结构如下所示:

.
??? build
?   ??? artifacts
?   ?   ??? test
?   ??? docs
?   ??? exe
?   ??? list
?   ??? logs
?   ??? obj
?   ??? temp
?   ??? test
?       ??? cache
?       ??? dependencies
?       ??? list.i
?       ??? mocks
?       ??? out
?       ??? results
?       ??? runners
?       ??? tests.map
??? project.yml
??? rakefile.rb
??? src
?   ??? main
?       ??? c
?       ?   ??? canDatabase.c
?       ??? include
?       ?   ??? canDatabase.h
?       ??? python
?       ??? resources
??? test
?   ??? support
?   ??? test_canDatabase.c
??? <my_project>.dep
??? <my_project>.ewd
??? <my_project>.ewp
??? <my_project>.eww
??? vendor
?   ??? ceedling
?       ??? docs
?       ??? lib
?       ??? plugins
?       ??? vendor
??? version.properties
Run Code Online (Sandbox Code Playgroud)

之后,按照@ user694733的建议,我查看了IAR工具的参考手册,并在构建示例项目时研究了IAR Embedded Workbench的输出。我使用此信息来编辑我的信息,project.yml如下所示:

:project:
  :use_exceptions: FALSE
  :use_test_preprocessor: FALSE
  :use_auxiliary_dependencies: TRUE
  :build_root: build
  :release_build: FALSE
  :test_file_prefix: test_

:environment:
  - :path:
    - 'C:\Program Files (x86)\IAR Systems\Embedded Workbench 6.5\arm\bin'
    - 'C:\Program Files (x86)\IAR Systems\Embedded Workbench 6.5\common\bin'
    - #{ENV['PATH']}

:extension:
  :executable: .out

:paths:
  :test:
    - +:test/**
    - -:test/support
  :source:
    - src/main/c/**
    - src/main/include/**
    - src/main/resources/**
  :support:
    - test/support

:defines:
  :commmon: &common_defines []
  :test:
    - *common_defines
    - TEST
  :test_preprocess:
    - *common_defines
    - TEST

:cmock:
  :mock_prefix: mock_
  :when_no_prototypes: :warn
  :enforce_strict_ordering: TRUE
  :plugins:
    - :ignore
    - :callback
  :treat_as:
    uint8:    HEX8
    uint16:   HEX16
    uint32:   UINT32
    int8:     INT8
    bool:     UINT8

:tools:
  :test_compiler:
    :executable: iccarm
    :name: 'IAR test compiler'
    :arguments:
      - -D _DLIB_FILE_DESCRIPTOR=1
      - --debug
      - --endian=little
      - --cpu=Cortex-M3
      - -e
      - --fpu=None
      - -Ol
      - --preprocess "build/test/list"
      - --dlib_config "C:/Program Files (x86)/IAR Systems/Embedded Workbench 6.5/arm/INC/c/DLib_Config_Normal.h"
      - -I"$": COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE
      - -I"$": COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR
      - -o "${2}"
      - --diag_suppress=Pa050
      - '"${1}"'

  :test_linker:
    :executable: ilinkarm
    :name: 'IAR test linker'
    :arguments:
      - --vfe
      - --redirect _Printf=_PrintfFull
      - --redirect _Scanf=_ScanfFull
      - --semihosting
      - --config "C:/Program Files (x86)/IAR Systems/Embedded Workbench 6.5/arm/config/generic_cortex.icf"
      - --map "build/test/tests.map"
      - -o "${2}"
      - '"${1}"'

  :test_fixture:
    :executable: cspybat
    :name: 'CSpyBat test runner'
    :arguments:
      - '"C:\Program Files (x86)\IAR Systems\Embedded Workbench 6.5\arm\bin\armproc.dll"'
      - '"C:\Program Files (x86)\IAR Systems\Embedded Workbench 6.5\arm\bin\armsim2.dll"'
      - '"${1}"'
      - --plugin "C:\Program Files (x86)\IAR Systems\Embedded Workbench 6.5\arm\bin\armbat.dll"
      - --backend -B
      - --endian=little
      - --cpu=Cortex-M3
      - --fpu=None
      - --semihosting

:plugins:
  :load_paths:
    - vendor/ceedling/plugins
  :enabled:
    - stdout_pretty_tests_report
    - module_generator
...
Run Code Online (Sandbox Code Playgroud)

这似乎是用于测试旨在在Cortex-M3设备上工作的代码的合适配置。

我还进行了编辑,rakefile.rb以确保在每次测试运行之前都会清理生成的测试文件,因为这对于使测试结果一致地打印是必要的。

PROJECT_CEEDLING_ROOT = "vendor/ceedling"
load "#{PROJECT_CEEDLING_ROOT}/lib/ceedling.rb"

Ceedling.load_project

task :default => %w[ clean test:all ]
Run Code Online (Sandbox Code Playgroud)

然后,我能够定义和运行单元测试。以下摘录自test_canDatabase.c

#include "unity.h"
#include "canDatabase.h"

uint32_t actualId;
uint8_t actualPayload[8];
uint8_t actualPayloadLen;
uint8_t actualCanPort;

void mockHandler(uint32_t id, uint8_t payload[8], uint8_t payloadLen, uint8_t canPort)
{
  actualId = id;
  actualPayloadLen = payloadLen;
  actualCanPort = canPort;

  for (int i=0; i < payloadLen; i++)
  {
    actualPayload[i] = payload[i];
  }
}

void setUp(void)
{
  actualId = 0;
  actualPayloadLen = 0;
  actualCanPort = 0;

  for (int i=0; i < 8; i++)
  {
    actualPayload[i] = 0;
  }

  CANDB_Init(mockHandler);
}

void tearDown(void) {}

void test_Register_Tx_Definition()
{
  // GIVEN a CAN Tx message definition.
  CAN_TX_MESSAGE_DEFINITION_T definition;
  definition.id = 0;

  // WHEN we register the definition in the CAN database.
  int err = CANDB_RegisterTxDefinition(definition);

  // THEN the database should return SUCCESS (0x0).
  TEST_ASSERT_EQUAL_MESSAGE(0x0, err, "Registration should succeed");
}

void test_Register_Tx_Definition_Twice()
{
  // GIVEN a CAN Tx message definition.
  CAN_TX_MESSAGE_DEFINITION_T definition;
  definition.id = 0;

  // WHEN we register the definition once.
  CANDB_RegisterTxDefinition(definition);

  // AND we register the definition again.
  int err = CANDB_RegisterTxDefinition(definition);

  // THEN the database should return SUCCESS (0x0).
  TEST_ASSERT_EQUAL_MESSAGE(0x0, err, "Re-registration should succeed");
}
Run Code Online (Sandbox Code Playgroud)

我现在可以通过从终端(项目根是当前工作目录)中调用“ ceedling”来运行自动化测试:

$ ceedling
---------------------
BUILD FAILURE SUMMARY
---------------------
Unit test failures.


Cleaning build artifacts...
(For large projects, this task may take a long time to complete)



Test 'test_canDatabase.c'
-------------------------
Generating runner for test_canDatabase.c...
Compiling test_canDatabase_runner.c...
Compiling test_canDatabase.c...
Compiling unity.c...
Compiling canDatabase.c...
Compiling cmock.c...
Linking test_canDatabase.out...
Running test_canDatabase.out...

-----------
TEST OUTPUT
-----------
[test_canDatabase.c]
  - ""
  - "     IAR C-SPY Command Line Utility V6.6.0.2752"
  - "     Copyright 2000-2013 IAR Systems AB."
  - ""
  - ""

-------------------
FAILED TEST SUMMARY
-------------------
[test_canDatabase.c]
  Test: test_Register_More_Than_Max_Allowed_Definitions
  At line (84): "Expected 1 Was 0. Registration > CANDB_MAX_TX_DEFINITIONS should fail"

  Test: test_Activate_Tx_Definition_With_Hardcoded_Payload
  At line (124): "Expected 0x00000001 Was 0x00000000. Incorrect ID"

--------------------
OVERALL TEST SUMMARY
--------------------
TESTED:  4
PASSED:  2
FAILED:  2
IGNORED: 0
Run Code Online (Sandbox Code Playgroud)