Main Content

本页采用了机器翻译。点击此处可查看英文原文。

使用 API 命令导入单元测试的自定义代码

此示例展示如何使用 API 将热泵控制器的自定义 C 代码导入 Simulink 进行单元测试。单元测试独立于自定义代码库测试一个或多个函数。对于单元测试,Simulink Test 代码导入器从指定的自定义代码生成一个测试沙箱和一个包含 C Caller 模块的库。

热泵控制器自定义代码文件

热泵控制器的完整代码位于以下 C 代码源和头文件中:

源文件位于 src 目录中:

  • tempController.c

  • utils.c

头文件位于 include 目录中:

  • tempController.h

  • utils.h

  • controllerTypes.h

tempController.c 文件包含热泵机组的自定义 C 代码的算法。该文件中的 heatpumpController 函数使用室温 (Troom_in) 和设定温度 (Tset) 作为输入。输出是 pump_control_bus 类型结构体,其信号控制风扇、热泵以及热泵的方向(加热或冷却)。pump_control_bus 结构体具有以下字段:fan_cmdpump_cmdpump_dirpump_control_bus 结构体类型在 controllerTypes.h 文件中定义。heatpumpController 函数的输出是:

TemperatureSystemFanPumpPumpConditionStateCommandCommandDirection|Troom_in - Tset| < DeltaT_fanIdle00IDLEDelatT_fan <= |Troom_in - Tset| < DeltaT_pumpFan only10IDLE|Troom_in - Tset| >= DeltaT_pump and Tset < Troom_inCooling11COOLING|Troom_in - Tset| >= DeltaT_pump and Tset > Troom_inHeating11HEATING

heatpumpController 函数使用了两个实用函数 absoluteTempDifference pumpDirection,它们在 utils.c 文件中定义。absoluteTempDifference 函数以双精度形式返回 Tset Troom_in 之间的绝对差。pumpDirection 函数返回以下 PumpDirection 类型枚举值之一:

Temperature ConditionPump DirectionTset < Troom_inCOOLINGTset > Troom_inHEATING

PumpDirection 枚举 typecontrollerTypes.h 文件中定义。

导入热泵控制器代码并自动创建桩件

此示例仅使用 tempController.c 创建测试沙箱并将其导入 Simulink。您使用沙箱仅对 heatpumpController 函数执行单元测试,而不是对完整代码执行单元测试。生成沙盒会自动为 heatpumpController 函数、absoluteTempDifferencepumpDirection 使用的实用函数创建桩件。由于实用函数未在 tempController.c 文件中定义,且未包含 utils.cutils.h 文件,因此代码导入器会创建桩件,因此代码不会出错。

设置 CodeImporter 对象

为热泵控制器自定义代码创建一个 CodeImporter 对象的实例。将 OutputFolder 属性设置为 $pwd$ 会将 $ 符号之间的字符串评估为 MATLAB 表达式。将 OutputFolder 设置为 $pwd$ 以指定当前文件夹作为输出文件夹。将 SourceFiles 属性设置为 src 目录中的 tempController.c 文件。也使用 $ 符号来指定 CustomCode 属性的文件位置。

obj = sltest.CodeImporter('heatpumpController');

obj.OutputFolder = "$pwd$";

obj.CustomCode.SourceFiles = "$fullfile('src','tempController.c')$";
obj.CustomCode.IncludePaths = fullfile('include');
obj.CustomCode.GlobalVariableInterface = true;

创建测试沙盒

使用所需的测试类型和沙盒设置配置 CodeImporter 对象。

要为自定义代码中的指定 heatpumpController 函数创建测试沙盒,请设置 TestType 属性 UnitTest。对于此示例,使用 GenerateAggregatedHeader 沙盒模式。有关不同沙盒模式的信息,请参阅 sltest.CodeImporter.SandboxSettings

SandboxSettings.CopySourceFiles 设置为 true 会将指定的源文件复制到测试沙箱中。

请注意,您只能对单个源文件使用 GenerateAggregatedHeader 沙盒模式。

obj.TestType = "UnitTest";

obj.SandboxSettings.Mode = "GenerateAggregatedHeader";
obj.SandboxSettings.CopySourceFiles = true;

创建沙盒。此测试沙箱与原有的自定义代码库是隔离的。如果存在,将 Overwrite 设置为 on 会覆盖现有的测试沙盒。默认情况下,Overwriteoff

obj.createSandbox('Overwrite','on'); 

createSandbox 方法在指定的输出文件夹中创建 heatpumpController_sandbox 目录,在此示例中该文件夹为当前工作文件夹。

沙盒目录包含以下子目录:

  • src:该目录包含复制的源文件 tempController.c

  • include:该目录包含在沙箱 src 目录中编译 tempController.c 所需的包含文件。该目录还包含 aggregatedHeader.h 文件,其中包含编译 tempController.c 所需的所有符号。

  • autostub:此目录包含 auto_stub.cauto_stub.h 文件,其中保存了 absoluteTempDifference pumpDirection 实用函数 . 的自动生成的桩件

  • manualstub:该目录包含 man_stub.cman_stub.h 文件,它们定义任何手动指定的桩件。默认情况下,这些文件没有定义任何函数。

导入测试沙盒

将沙盒代码导入 Simulink。

obj.import('Functions','heatpumpController');

import 函数创建沙盒。它还创建一个包含名为 heatpumpController 的 C Caller 模块的库,该库包含一个内部测试框架,您可以使用它对 heatpumpController 执行单元测试。该库附加到 Simulink 数据字典,该字典分别将 pump_control_busPumpDirection 定义为 Simulink.Bus 对象和 Simulink 枚举信号。

C Caller 模块附带一个内部测试框架,用于对 heatpumpController 函数进行单元测试。

C Caller 模块上的输入和输出端口

因为在导入之前将 CustomCode.GlobalVariableInterface 设置为 true,所以 import 函数会为 auto_stub.c 中的 absoluteTempDifferencepumpDirection 全局变量创建桩件并为它们创建端口。有关信息,请参阅 Enable global variables as function interfaces

这是从 heatpumpController 函数生成的 C Caller 模块,heatpumpController

Heat pump controller showing input and output ports

这些是 auto_stub.c 文件中为 absoluteTempDifferencepumpDirection: 自动生成的全局变量

/*************************************************************************/
/* Generated Global Variables for Stubbed Functions Interface            */
/*************************************************************************/
double SLStubIn_absoluteTempDifference_p1;
double SLStubIn_absoluteTempDifference_p2;
double SLStubOut_absoluteTempDifference;
double SLStubIn_pumpDirection_p1;
double SLStubIn_pumpDirection_p2;
PumpDirection SLStubOut_pumpDirection;

double absoluteTempDifference( double absoluteTempDifference_p1, double  absoluteTempDifference_p2)
{
  SLStubIn_absoluteTempDifference_p1 = absoluteTempDifference_p1;
  SLStubIn_absoluteTempDifference_p2 = absoluteTempDifference_p2;
  return SLStubOut_absoluteTempDifference;
}


PumpDirection pumpDirection( double pumpDirection_p1, double pumpDirection_p2)
{
  SLStubIn_pumpDirection_p1 = pumpDirection_p1;
  SLStubIn_pumpDirection_p2 = pumpDirection_p2;
  return SLStubOut_pumpDirection;
}

absoluteTempDifference 函数自动生成的桩件中,全局变量 SLStubIn_absoluteTempDifference_p1SLStubIn_absoluteTempDifference_p2 保存了该函数的输入参量。该函数返回存储在 SLStubOut_absoluteTempDifference 中的值。类似地,pumpDirection 保存输入参量并返回 SLStubOut_pumpDirection

要使用通过自动创建的桩件创建的测试框架,请参阅下图。为输入和输出添加总线。为了能够连接 Simulink 信号进行仿真,请连接 TsetTroom_in 的输入以及全局变量 SLStubOut_absoluteTempDifferenceSLStubOut_pumpDirection 的预期输出,同样,按照图中所示连接输出。您可以使用输入和输出来观测 heatpumpController 传递给 absoluteTempDifferencepumpDirecton 子函数调用的内部值。

Test harness for heat pump controller

将自动创建的桩件更改为手动桩件

例如,如果您想生成桩件的预期输出作为自动生成端口的输入,您可以用手动桩件替代创建沙箱时自动生成的桩件。切换到使用手动桩件后,您可以更新现有的沙箱并再次导入它。

手动修改自动生成的桩件函数

您可以通过更新 manualstub 目录中的 man_stub.cman_stub.h 文件来手动为自动生成的桩件函数提供定义。

manualstubpath = fullfile([obj.LibraryFileName.char '_sandbox'],'manualstub');
helperFunctionToUpdateManualStubs(manualstubpath);

helperFunctionToUpdateManualStubs 函数更新测试沙箱中的手动桩件文件。

更新后的 absoluteTempDifference 函数定义如下:

double absoluteTempDifference(double Tset, double Troom_in){ 
    return (double)fabs(Tset - Troom_in);
}

更新后的 pumpDirection 函数定义如下:

PumpDirection pumpDirection(double Tset, double Troom_in){
    return Tset > Troom_in ? HEATING : COOLING;
}

更新现有的测试沙盒

要使用手动桩件功能,请更新沙箱以反映您的更改。将 Overwrite 选项设置为 off 会保留对测试沙箱中 manualstub 目录所做的更改。

obj.createSandbox('Overwrite','off');

更新测试沙箱后,自动桩件目录为空,因为您在指定的自定义代码中定义了所有未定义的符号。

导入更新的测试沙盒

更新测试沙盒后,将沙盒代码导入 Simulink。

obj.import('Functions','heatpumpController');

该库包含一个名为 heatpumpController 的 C Caller 模块,其端口已更新,并且附加到 C Caller 模块的内部测试框架也已更新。

导入函数更新现有库并导入 heatpumpController 函数。就像使用自动生成的桩件时一样,该库附加到 Simulink 数据字典,该字典分别将 pump_control_busPumpDirection 定义为 Simulink.Bus 对象和 Simulink 枚举信号。

C Caller 模块端口反映了对桩件文件所做的更改。由于 absoluteTempDifferencepumpDirection 函数的手动实现没有使用任何全局变量,因此 C Caller 模块仅具有 heatpumpController 函数的输入参量和返回参量的端口。连接到 C Caller 模块的内部测试框架也已更新。

heatpumpController_man_stub.jpg

您可以使用创建的 MLDATX 测试文件来测试代码。请参阅使用向导对导入的自定义代码进行单元测试了解测试示例。

另请参阅

| | | | | | |

相关主题