首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >嵌入式系统的Google测试

嵌入式系统的Google测试
EN

Stack Overflow用户
提问于 2020-03-05 18:58:36
回答 2查看 8.2K关注 0票数 3

我想用谷歌测试为我的嵌入式应用软件编写单元测试。

这些测试将在应用软件上执行,应用软件是用C++编写的。应用软件使用的驱动程序(如。I2CSPI),错误断言是用C编写的。我的问题是:

  1. 什么地方是开始的好地方?我指的是我可以阅读的更多关于在嵌入式环境中使用Google的资源。
  2. 我该如何去模仿我的驱动程序文件?例如,如果我在我的void read(uint8_t address)库中有一个I2C函数,我如何模拟这个函数,以便在我的C++类中调用这个特定的函数?
  3. 用C编写的这些驱动程序文件也包含在我的C++文件中。我试着编译一个裸露的测试文件,只包括我的C++类头,并且存在编译问题,因为编译器找不到驱动程序头。我怎样才能避免这个问题?
  4. 使用我的驱动程序库中的失败断言管理失败的断言,调用系统重置。我怎样才能在测试中模仿这个呢?
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-12-10 16:40:44

最近,我用gTest (GoogleTest)测试了一个用于Arm Cortex-M3内核的FAT文件系统和引导加载器实现,所以我将留下我的两分钱。

嵌入式软件测试存在这样的问题:不可能通过模拟复制HW环境。我想出了三套测试:

( A)在我的PCTDD上运行的单元测试(我在中使用)。我使用这些测试来开发应用程序逻辑。这就是我需要嘲弄/固执的地方。我的公司使用硬件抽象层(HAL),这正是我所嘲笑的。如果您想要编写可测试的代码,这最后一点是基本的。

代码语言:javascript
复制
/* this is not testable */
my_register->bit0 = 1;

/* this is also not testable */
*my_register |= BIT0;

不要直接访问寄存器,使用可以模拟的简单HAL包装器功能:

代码语言:javascript
复制
/* this is testable */
void set_bit(uint32_t* reg, uint8_t bit)
{
    *reg |= bit;
}

set_bit(my_register , BIT0);

后者是可测试的,因为您将模拟set_bit函数,从而打破了对HW的依赖。

( B)对目标进行单元测试。这是一个比(A)小得多的测试集,但是它仍然非常有用,特别是对于测试驱动程序和HAL函数。这些测试背后的想法是,我可以正确地测试我将要模拟的函数。因为这是在目标上运行的,所以我需要尽可能简单和轻量级,所以我使用MinUnit,它是一个单一的C头文件。我在Cortex-M3核和专有的DSP代码上运行了MinUnit的目标测试(没有任何修改)。我在这里也用过TDD。

( C)综合测试。我使用Python并在这里进行操作,在目标上构建、下载和运行整个应用程序。

回答你的问题:

  1. 正如其他人已经说过的,从gTest底漆开始,不要担心嘲笑,只需要掌握使用gTest的诀窍。Cpputest是一个很好的替代方案,它提供了一些内存检查(用于检查泄漏)。我对派生安装类的gTest语法略感兴趣。Cpputest可以运行用gTest编写的测试。两者都是很好的框架。
  2. 我用假函数框架来嘲弄和固执。它使用起来非常简单,而且它提供了一个很好的模拟框架所期望的一切:设置不同的返回值、传递回调、检查参数调用历史等等。我想让塞德林试一试。到目前为止,FFF一直很棒。
  3. 我不会那么做的。我用C++编译器(在我的例子中是g++)编译测试框架和测试,用C编译器(gcc)编译嵌入式代码,并将它们链接到一起。从下面的示例中,您将看到我没有在C文件中包括C++头。当链接您的测试时,您将链接除C源文件之外的所有用于您所模拟的函数的所有内容。

使用我的驱动程序库中的失败断言管理失败的断言,调用系统重置。我怎样才能在测试中模仿这个呢?

我会嘲笑重置函数,添加一个回调到“重置”您需要的任何东西。

假设您想测试使用read_temperature函数的read函数。下面是一个使用FFF进行模拟的gTest示例。

hal_i2c.h

代码语言:javascript
复制
/* HAL Low-level driver function */
uint8_t read(uint8_t address);

read_temperature.h

代码语言:javascript
复制
/* Reads the temperature from the I2C sensor */
float read_temperature(void);

read_temp.c

代码语言:javascript
复制
#include <hal_i2c.h>

float read_temperature(void)
{
    unit8_t raw_value;
    float temp;

    /* Read the raw value from the I2C sensor */
    raw_value = read(0xAB);

    /* Convert the raw value */
    temp = ((float)raw_value)/0.17+273;
    return temp;
}

test_i2c.cpp

代码语言:javascript
复制
#include <gtest/gtest.h>
#include <fff.h>

extern "C"
{
#include <hal_i2c.h>
#include <read_temperature.h>
}

DEFINE_FFF_GLOBALS;
// Create a mock for the uint8_t read(uint8_t address) function
FAKE_VALUE_FUNC(uint8_t , read, uint8_t);

TEST(I2CTest, test_read) {

    // This clears the FFF counters for the fake read() function
    RESET_FAKE(read);

    // Set the raw temperature value
    read_fake.return_val = 0xAB;

    // Make sure that we read 123.4 degrees
    ASSERT_EQ((float)123.4, read_temperature());
}

对于具有测试类的更复杂的测试场景,可以在RESET_FAKE方法中调用SetUp()

希望这能有所帮助!干杯!

票数 6
EN

Stack Overflow用户

发布于 2020-03-06 12:14:32

  1. 我不知道使用Gtest进行裸金属目标测试的任何特定资源,但一般来说,一个很好的起点是阅读格泰底漆,并依赖您的软件体系结构(甚至Gmock文档 )。后者在测试应用程序相关类时可能会很有用,而不仅仅是低级驱动程序。
  2. 这方面有几种选择。到目前为止,我看到的最常见的实现是为目标和运行测试的平台提供两个不同的实现。例如,你可能有两个文件
代码语言:javascript
复制
- ic2.c
- i2c\_x86.cpp

取决于您当前是否正在为目标或测试平台进行编译,您可以使用它们中的任何一种。

另一种选择是将C实现提升到C++,并在驱动程序周围编写类包装器。这将允许您从C++特性中获益,并使用依赖注入、继承、CRTP等.

  1. 我不知道你想要什么。
  2. Gtest有一个ASSERT_DEATH测试,例如我当前的代码库包含以下测试
代码语言:javascript
复制
      // 2 byte message does not fit 14bit, assertion triggered
      ASSERT_DEATH(encode_datagram(make_datagram(0, 64, 0)), ".*");
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60552301

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档