Forums

Assert()如果您乐橙云app前后条件

开始于 韦丹 3 months ago6回复最新回复3个月前91浏览

我正在尝试乐橙云app驱动开发(TDD),希望能得到一些建议。如果您是从事TDD或单元乐橙云app的工程师,我想知道您是否还要在函数前置和后置条件或类/结构不变式(即合同)上乐橙云app功能。

我正在观看约翰·拉科斯(John Lakos)关于他在彭博社的团队如何将合同外使用视为未定义行为的非常有趣的演讲,但是在内部,他们出于设计严格性的目的验证了自己的防御性检查是否违反了前后条件。这是 part 1part 2 of the talk.

在网上阅读时,对于乐橙云app违反合同的行为似乎有各种意见。有人解释说,从合约中调用函数是编程错误(我同意),但是单元乐橙云app的目的是仅评估定义良好(或合约中)的函数行为。但是,在我看来,这类防御性检查很重要-尤其是在代码是库的情况下-不验证防御性检查会使它们的价值降低。

你有什么感想?您是否在库或主要逻辑中使用防御性检查?您是否检查前后条件?在运行乐橙云app时,如何验证这些检查是否正确?

谢谢,

丹尼尔

[-]
回覆者 QL2020年11月5日

我总是很高兴看到有关嵌入式代码中断言的讨论,因为正如Bertrand Meyer(按合同设计的发明者)所说:“ ...这使对软件错误的整个讨论有了全新的视角...” 。

为了重新定义TDD和断言之间的关系,我从TDD社区听说,它们使用的断言不多,“因为TDD只产生经过*乐橙云app的*代码,不需要断言”。因此,大多数单元乐橙云app框架都不允许您乐橙云app断言失败。我的意思是编写有意违反断言的单元乐橙云app,因此断言失败时乐橙云app将成功。乐橙云app断言失败的能力也与重置CUT(被测代码)的概念密切相关,因为除非系统恢复到已知良好状态,否则失败断言后的任何乐橙云app通常都没有意义。遗憾的是,大多数单元乐橙云app框架都不允许您干净地重置CUT(setup()/ teardown()函数不够好)

关于“单元乐橙云app的目的仅是评估明确定义的(或合同中的)行为”的信念,我认为这适得其反。单元乐橙云app的目的是彻底*乐橙云app* CUT,包括合同外的情况。

最后,对我来说真正有趣的问题(我不确定约翰·拉科斯的演讲是否很清楚)是 将断言保留在生产代码中。我在很多场合都写过并写过博客(例如, “保险丝的钉子” or “异常或错误”)。

[-]
回覆者 马修·埃斯莱曼2020年11月5日

丹尼尔,您好

TDD是增加您的工程技能的绝佳工具。 我个人喜欢.

我认为对于大多数具有典型日历和预算约束的消费者级固件/软件项目而言,专门针对asserts / DBC编写单元乐橙云app可能无法带来最大的收益。话虽如此,我希望安全相关代码考虑对断言/合同进行单元乐橙云app。

您是否在库或主要逻辑中使用防御性检查? 

是的。

您是否检查前后条件?

我个人主要关注前提条件。我的大多数项目都是消费者级的,因此倾向于交付所需的价值/质量。

在运行乐橙云app时,如何验证这些检查是否正确?

我一般没有。显然,它们正在通过单元乐橙云app针对“合同中”或“非主张”案例进行乐橙云app。话虽这么说,但在少数情况下,我专门针对断言(或异常)编写了乐橙云app。确保您的单元乐橙云app框架能够处理断言乐橙云app。

并且,当然,请确保当固件确实触发断言时,会出现有用的(安全的)信息。几年前我从事的一个项目不小心切换了调试/生产构建标志,并且生产版本最终遇到了调试器断点,而不是执行适当的重置。啊。

综上所述,DBC / asserts是在项目中添加另一个Bug预防层的好方法。我最近整理的其他一些想法(包括断言)在这里:

//covemountainsoftware.com/2020/08/16/stoppi...

希望能有所帮助,

马修

[-]
回覆者 mr_bandit2020年11月5日

我做关键任务系统并大量使用断言。以我的经验,70..80%(一个猜测,但粗略地说)来自数据结构未正确设置或未正确遍历它们。我同意马奎尔的主张(大部分情况下)

编写Solid Code(20周年2版)平装本-2013年1月1日,作者Steve Maguire(作者) //www.amazon.com/Writing-Solid-Code-20th-Ann...

例如:

#define TYPE_FOO   (0xDEAD)
#define TYPE_BAR   (0xBEEF)

typedef struct
{
    uint16_t  type;   // TYPE_BAR;
    (body)
} BAR;    

typedef struct
{
    uint16_t type;    // TYPE_FOO
    BAR  *bar;
    (body)
} FOO;

void use_foo( FOO *foo )
{
    BAR *bar;
    assert( foo );     // non-null    
    assert( foo->type == TYPE_FOO );  // and what I expected
    bar = foo->bar;
    assert( bar );
    assert( bar->type == TYPE_BAR );
    (body)
}

这是通过以下步骤进行的:注意检查栏

示例案例:我正在为演示程序编写一些代码&&想“啊-我将忽略整个断言数据结构的事情。”追了我的尾巴三天,进去了&&进行检查-在几分钟内发现了错误-我在结构树上走错了&&某些设置有误。

我不同意马奎尔的地方是:他主张以下顺序:

  • 用中的断言编译
  • 运行乐橙云app套件以取得成功
  • 断言编译
  • 运行您的乐橙云app套件

我只保留断言。

注意:您为TYPE选择的值应该较大,因为在大多数系统中,较小的数字是标准值。通过选择大数(例如0xDEnn),可以最大程度地减少为TYPE值选择编程值的可能性。

举例:我有一个T1时钟同步盒的演出。几年后,我与客户的一位同事交谈。他们添加了一些功能,并且陷入了我的断言之一。没有它,他们将有一个微妙的错误。

现在:如果要乐橙云app合同外的情况,则可以随时定义assert()。除了默认操作,您还可以执行适合框架的操作。然后,在乐橙云app之后,以对系统有用的方式对其进行定义。

例如,我在一个系统上定义它以将断言记录在EEPROM中&&然后重新启动系统。

还有另一方面要断言。我首先将它用于公共安全系统。它融入了客户现有的代码和精神。他们有一个很大的代码库,它假定了许多项目特定的表。该过程最终以run / assert / fix / run /的方式结束。一旦完成所有过程,您就会对代码的正确性充满信心。您找到了所有内部表&&错误的假设。 (他们还每天从凌晨2点开始进行完整的编译。)

(顺便说一句,在那场演出中,如果我们与4..5核心开发人员进行了一个小时的讨论, 需要使用一个 *** ptr 在特定情况下。决定这是最干净的方法。该行代码包含40..50条注释,描述了什么& why.)


[-]
回覆者 韦丹2020年11月6日

感谢Matthew,Miro和mr_bandit,感谢您提供的建议和新的签出资源。作为后续措施,您会推荐任何乐橙云app框架吗?我一直在看CppUTest-James Grenning在其中使用的 嵌入式C的乐橙云app驱动开发 -和具有良好API(但可能永远无法安装在目标设备上)的Catch2。如果您使用的框架可以很好地与断言配合使用,我将不胜感激。

谢谢,

丹尼尔

[-]
回覆者 QL2020年11月6日

>如果您使用的框架可以很好地与断言配合使用,我将不胜感激。

是的。如果您愿意走人迹罕至的地方,建议您检查一下 QUTest单元乐橙云app框架 (完整披露的QUTest由我公司提供 量子飞跃)。

如中所述 QUTest文档, this framework breaks up with the xUnit tradition. (And virtually all frameworks, including CppUTest and Unity, are based on xUnit). Instead, working with QUTest is similar to "debugging with printf" (or sprintf or similar), where you instrument the code to output information about its execution. You then run the code with a controlled set of inputs, and examine the produced output from the printfs to determine whether the code under test operates correctly. The main differences from using printfs are: (1) that the much more efficient QP /间谍 而是使用输出机制,(2)生成输入和乐橙云app输出的检查都是 自动化的.

这种乐橙云app策略使QUTest可以清晰地分开执行CUT(乐橙云app治具),从检查正确性(乐橙云app脚本)。这意味着可以使用与CUT(C或C ++)不同的语言来开发乐橙云app脚本。在QUTest中,乐橙云app脚本编写为 蟒蛇,据我所知,这是嵌入式系统唯一的单元乐橙云app框架,其中Python是单元乐橙云app不可或缺的一部分。

QUTest专用于乐橙云app断言,旨在支持 合同乐橙云app设计 (C或C ++中的断言,请勿与“乐橙云app断言”相混淆)。另外,QUTest支持 重置目标 for each individual test, if needed. This goes far beyond providing test setup() and teardown() functions that other testing frameworks offer (and of course QUTest supports as well).

[-]
回覆者 马修·埃斯莱曼2020年11月13日

对于断言友好框架,我没有具体建议。您可能需要一个构建选项,以适当的命中框架的宏替换标准的断言,并在适当的情况下确保在断言执行后没有代码。

话虽如此,我已经使用了您在商业软件项目中提到的所有框架以及Samek(QL)提到的框架。这里有一些想法。

对于大多数嵌入式/固件项目,我最喜欢的是CppUTest,它的乐橙云app在主机PC上运行,而不是在目标计算机上运行。我已经在多个项目中使用了它,并且对结果总体上感到满意。

我还使用了Catch2,它很容易。但是,它缺少了(或缺少)mock()框架,我认为大多数嵌入式软件项目都需要该框架。在我的情况下,正在编写/乐橙云app的代码比嵌入式代码更接近PC样式代码,因此效果很好。

我还在一些项目上使用过QUTest。我通常不建议基于目标的框架,仅是因为我是TDD倡导者,这意味着我经常运行关联的单元乐橙云app。任何目标上的框架(例如QUTest)都将大大降低速度,因为至少每个乐橙云app周期的执行都会产生将乐橙云app构建交付给目标的成本,而这往往很慢。在我从事的项目中,我用CPPUTest替换了各种基于QUTest的乐橙云app,正在乐橙云app的逻辑完全相同,乐橙云app周期从1分钟缩短到3秒或更短。话虽这么说,在那些项目中,我们最终混合在一起。所有高级和中级模块仅使用CppUTest,因此可以进行基于PC的单元乐橙云app。我们最低级别的模块(驱动程序)继续使用QUTest。我们认为这是正确的平衡,值得支持这两种方法。顺便说一句:我喜欢Samek的书和软件,我只是不喜欢目标乐橙云app方法。

基于主机的单元乐橙云app的另一个好处是,您可以轻松地将所有这些乐橙云app包含在标准的持续集成构建管道中,从而确保在每次提交时都执行所有可用的乐橙云app。非常好。使用目标乐橙云app框架很难做到这一点。

我在有关此问题的上一次演讲中提出了这些观点,以及更多内容,可在这里找到:

//covemountainsoftware.com/wp-content/upload...

最好的祝福,

马修