
嵌入式系统编程【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址https://gitcode.com/gh_mirrors/fpri/fprime点击查看免费下载导读STest 是 F´F Prime飞行软件与嵌入式系统框架中内置的一个单元测试框架其核心思想是用规则Rule与场景Scenario来构造并运行单元测试。本文以 STest/README.md 为骨架深入讲解 State、Rule、Scenario 三大核心概念并结合仓库中的源码实现如 Rule.hpp、Scenario.hpp与 F Prime 组件测试的真实用例如 Svc/GroundInterface 的测试说明如何用这种结构化的、可自动生成测试的方式替代手工编写海量用例提升组件测试的覆盖率与可维护性。为什么需要规则与场景单元测试的结构化革命在传统的单元测试中每个测试用例通常是一个独立的函数设置状态、执行被测逻辑、断言结果。当被测组件状态众多、行为交错时手工编写并维护这些用例会变得繁琐且容易遗漏边界。STest 的答案是把测试从用例集合提升为规则系统。它由三个基础概念构成State状态描述测试运行的当前状态Rule规则一段测试代码单元指定并检查被测系统system under test, SUT的某种行为Scenario场景一组规则的配方recipe用于构造一个或多个测试。STest 的设计目标非常明确为单元测试提供结构并通过自动生成测试获得手工编写难以企及的覆盖率——例如自动执行成千上万条规则这是手工编写不可行的。State规则与场景共同操作的状态类型在基于规则的测试中状态指的是运行中测试的当前状态。STest 将其分为两类具体状态concrete state被测系统SUT的真实状态测试状态 / 抽象状态test state / abstract state对被测系统状态的抽象建模用于辅助建模。从 Rule.hpp 与 Scenario.hpp 的实现可以看出Rule和Scenario都是以 State 为模板参数的 C 模板类templatetypename State。也就是说State 是用户自定义类型——既可以是简单结构也可以是承载被测组件上下文的测试器Tester对象。在实际的 F Prime 测试中State 常常就是组件测试器Tester本身。例如 Svc/GroundInterface/test/ut/TestMain.cpp 中Svc::Tester直接作为STest::RuleSvc::Tester与STest::RandomScenarioSvc::Tester的模板参数规则通过引用该 Tester 来驱动被测组件并收集断言结果。Rule行为的最小测试单元规则的构成一个规则Rule是描述被测系统某种行为的测试代码单元包含两个要素1. 前置条件precondition一个谓词函数只读、返回布尔值作用于 系统状态决定该规则何时可以应用。例如测试缓冲分配器buffer allocator的正常行为时前置条件可能是存在可分配的缓冲测试缓冲不可用这一错误路径时前置条件则可能是所有缓冲都已被分配。2. 动作action分两步完成——a驱动被测系统执行某种操作b在给定当前系统状态的前提下检查结果行为是否符合预期。例如分配器的正常 / OK规则会检查缓冲确实被分配缓冲不可用规则会检查是否发出了相应的 F 事件event告警。如何编写规则在 STest 中规则是抽象类Rule的派生类需要覆盖Rule接口中声明的两个纯虚函数。从 Rule.hpp 的源码可见其完整契约bool precondition(const State state) 0;前置条件谓词只读地检查状态void action(State state) 0;执行动作可修改状态void apply(State state)应用规则——先断言前置条件成立否则输出precondition failed applying rule name再调用action(state)构造函数接收规则名nameconst char*该名称会在场景运行日志中用于标识规则。一个最小示例以 GroundInterface 的真实规则为参照见 GroundInterfaceRules.cpp// 定义一条随机化上行参数的规则 struct RandomizeRule : public STest::RuleTester { explicit RandomizeRule(const char* const name) : STest::RuleTester(name) {} bool precondition(const Tester state) override { return true; // 随时可以随机化 } void action(Tester state) override { state.m_uplink_type STest::Pick::lowerUpper(0, 1); state.m_uplink_size STest::Pick::lowerUpper(0, sizeof(state.m_uplink_data) - 1); // ... 其余驱动被测组件、收集断言的逻辑 state.update_header_info(); } };规则接口的三个抽象方法Scenario基类Scenario.hpp是所有场景的抽象基类它为所有场景定义了三个必须实现的纯虚接口void reset_Scenario()重置场景状态RuleState* nextRule_Scenario(State state)返回下一个要应用的规则假设isDone()为 false没有则返回 NULLbool isDone_Scenario() const查询场景是否结束。场景提供统一的run(State state)入口其内部runHelper循环执行重置 → 取下一规则 → 应用规则 → 计数步数 → 判断是否结束直到没有更多规则可应用为止并返回实际执行的步数U32 numSteps。此外若当前目录存在show-rules文件场景在应用每条规则前会打印[Scenario name] Applying rule name日志便于调试见 Scenario.hpp。Scenario规则的配方场景Scenario是用一组规则构造一个或多个测试的配方。它把规则的选取、重复、组合逻辑抽象出来让测试作者用很简单的规格构建复杂的测试序列。仓库 Scenario 目录下提供了十余种场景下面按 README 列举逐一说明附源码路径。序列类场景固定与随机RuleSequenceScenario以固定顺序应用一组规则。它由SequenceScenario派生内部把规则数组逐条包装成RuleScenario每条规则只应用一次。RandomScenario以随机顺序应用一组规则。它由InterleavedScenario派生内部把每条规则包装成RepeatedRuleScenario见下文从而在随机交错的同时允许单条规则被反复命中。重复类场景反复应用与条件终止RepeatedRuleScenario在场景内重复应用一条规则。其isDone_Scenario()恒返回false只要前置条件成立就持续返回该规则直到由外层场景如 Bounded 或 Random 场景决定何时终止。ConditionalScenario在某个条件成立时运行一个场景。RepeatedScenario重复运行一个子场景内部由IteratedScenario派生重置时同步重置子场景并读取其结束状态。组合类场景顺序、选择与交错SequenceScenario创建一系列场景并按顺序运行。SelectedScenario从一组场景中随机选择一个运行。InterleavedScenario随机交错运行一组场景——这正是RandomScenario随机化多条规则的基础。ScenarioArray承载场景数组供SequenceScenario与InterleavedScenario使用。迭代与有界类场景控制运行次数IteratedScenario迭代一个场景集合。ConditionalIteratedScenario迭代一个特定场景直到某个条件成立。BoundedIteratedScenario以固定的迭代次数上界运行一个迭代场景。BoundedScenario运行场景固定次数次数上限固定。RandomlyBoundedScenario运行场景达到一个随机选择的上界次数上限随机。正是这些迭代类与随机类场景让测试作者可以用非常简单的规格构造出探索大量行为的复杂测试——它们通常会执行成千上万甚至数百万条规则这在手工编写条件下是不可行的README 对此有明确说明。随机支持Random 与 Pick随机场景与随机有界场景都依赖 STest 提供的随机数设施理解它们有助于正确使用随机化测试Random.hpp随机数生成。Random::seed()按优先从seed文件读取种子否则用当前时间并将种子追加写入seed-history文件的策略播种详见 Random.hpp 注释startLength(start, length)、lowerUpper(lower, upper)分别返回区间[start, startlength-1]与[lower, upper]内的随机数inUnitInterval()返回[0,1]区间的双精度值。底层随机数实现位于 STest/Random 目录的Random.cpp与bsd_random.c。Pick.hpp便捷取值接口提供inUnitInterval()、startLength(...)、lowerUpper(...)与any()任意 U32。在 GroundInterface 测试中STest::Pick::lowerUpper(0, 1)被用来随机选择上行类型、随机化上行数据字节见 GroundInterfaceRules.cpp。在 F Prime 中的实际应用README 明确指出目前 F Prime 使用 STest 进行组件的单元测试典型例子包括Svc/GroundInterface与Fw/Logger的测试。其使用模式主要有两种短规则序列先用若干规则搭建系统状态再用一条特定规则完成针对性测试随机场景自动生成更复杂的测试。完整用例剖析Svc/GroundInterface 的随机化测试Svc/GroundInterface/test/ut/TestMain.cpp 是一个教科书级的 STest 组合用法完整展示了定义规则 → 组装随机场景 → 套上有界场景 → 运行的流程#define STEP_COUNT 10000 TEST(Nominal, RandomizedGroundIf) { Svc::Tester tester; // 1. 创建规则并放入数组 Svc::RandomizeRule randomize(Randomize); Svc::DownlinkRule downlink(Downlink); Svc::FileDownlinkRule filedown(File Down); Svc::SendAvailableRule sendup(); STest::RuleSvc::Tester* rules[] { randomize, downlink, filedown, sendup }; // 2. 构造随机场景随机选择上述规则反复应用 STest::RandomScenarioSvc::Tester random(Random Rules, rules, FW_NUM_ARRAY_ELEMENTS(rules)); // 3. 套上有界场景限定最多运行 10000 步 STest::BoundedScenarioSvc::Tester bounded(Bounded Random Rules Scenario, random, STEP_COUNT); // 4. 运行并打印实际步数 const U32 numSteps bounded.run(tester); printf(Ran %u steps.\n, numSteps); }其依赖的规则定义在 GroundInterfaceRules.cpp 中每条规则继承STest::RuleTester重写precondition此处大多恒为true与action在 action 中调用 Tester 的invoke_to_*Port驱动被测组件端口再用assert_from_*断言输出端口行为最后clearFromPortHistory()清空端口历史。从该用例可以看到 STest 在 F Prime 测试中的完整链路状态Svc::Tester组件测试器作为模板参数贯穿所有类规则四条行为各异的规则封装不同上行/下行/文件传输行为场景组合RandomScenario随机交错内嵌于BoundedScenario固定 10000 步上界一次测试即可自动覆盖大量随机交错的行为序列可验证输出bounded.run(tester)返回实际执行步数可直接观测测试强度。此外Fw/Logger 的单元测试同样采用 STest 规则化测试见 Fw/Logger 目录下的测试文件印证了 STest 在 F Prime 组件测试中的通用地位。构建与集成STest 以 CMake 静态库形式集成STest/CMakeLists.txt 将其构建为名为STest的库编译源包括Random.cpp、bsd_random.c、Pick_default.cpp与Pick.cpp并把STest目录加入公开头文件搜索路径target_include_directories(STest PUBLIC ...)。测试代码只需通过#include STest/Scenario/...、#include STest/Pick/Pick.hpp等头文件引入相应场景与工具即可如 TestMain.cpp 所示。设计要点与最佳实践小结综合 README 与源码使用 STest 时有几个值得注意的要点前置条件是只读谓词precondition(const State)接收 const 状态保证规则选择阶段不会污染状态所有状态变更都应发生在action(State)中。规则命名用于诊断Rule与Scenario都携带名称结合show-rules文件Scenario.hpp场景会打印每条被应用规则的名称方便追踪随机化测试的执行路径。分层组合场景单一场景解决单一问题一次、重复、条件、有界、随机、交错……复杂测试通过场景嵌套实现——这正是 GroundInterface 用例RandomScenario 套 BoundedScenario的做法。用随机化换覆盖率迭代与随机场景天然适合探索大量行为的测试需求执行成千上万步的随机序列是手工用例无法企及的但要注意配合固定种子Random::seed()的种子文件机制以便复现失败用例。状态即测试器在 F Prime 中State 通常直接使用组件 Tester规则驱动端口调用并断言端口历史与 gtest 的断言ASSERT_TRUE等见 testing.hpp无缝衔接。结语STest 以状态 规则 场景的三元模型为 F´ 组件的单元测试提供了既结构化又高度自动化的方案规则封装行为与预期场景封装组合与执行策略随机与迭代场景则把测试强度提升到手工难以达到的量级。通过本文介绍的源码接口与 GroundInterface 真实用例读者已经具备在自己的 F´ 组件测试中引入 STest 规则化测试的完整路径——定义 Tester 状态、编写 Rule 派生类、用 Bounded/Random 等场景组合运行即可获得高覆盖、可复现、易维护的组件测试套件。赞分享嵌入式系统编程【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址https://gitcode.com/gh_mirrors/fpri/fprime点击查看免费下载相关推荐F´ 组件测试框架 STest 完全指南用规则与场景驱动的结构化单元测试F´ 组件测试框架 STest 完全指南用规则与场景驱动的结构化单元测试 导读 STest 是 F´F Prime飞行软件与嵌入式系统框架内置的测试框架嵌入式系统编程F Prime 中的 STest 规则与场景驱动测试框架以 Rule 和 Scenario 构建自动化单元测试F Prime 中的 STest 规则与场景驱动测试框架以 Rule 和 Scenario 构建自动化单元测试 STestScenario Test是 F嵌入式系统编程F´ DpManager 组件单元测试设计解析基于 STest 规则引擎的抽象状态、规则组与随机场景测试F´ DpManager 组件单元测试设计解析基于 STest 规则引擎的抽象状态、规则组与随机场景测试 导读 Svc::DpManager 是 F´ 飞行软嵌入式系统编程上一篇5分钟上手SWAGDocker新手必备的HTTPS服务器搭建教程下一篇成本降低56%Qwen2.5-VL-72B-Instruct-quantized.w8a8云部署经济性分析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考