用:Arianna Blasi, Alberto Goffi, Konstantin Kuznetsov, Alessandra Gorla, Michael D. Ernst, Mauro Pezzè, and Sergio Delgado Castellanos. 2018. Translating Code Comments to Procedure Specifications. In Proceedings of 27th ACM SIG- SOFT International Symposium on Software Testing and Analysis (ISSTA’18). ACM, New York, NY, USA, 12 pages. https://doi.org/10.1145/3213846.3213872.
过程规范在许多软件开发任务中很有用。例如,在自动生成测试用例的过程中,它们可以指导测试,充当能够发现错误并识别非法输入的测试先知。尽管实际上很少有正式的规范,但是对于开发人员来说,使用半结构化注释来记录其代码是标准做法。这些注释通过预定义标签和自然语言的组合来表达过程规范。本文介绍了 Jdoctor,该方法结合了模式,词法和语义匹配,将 Javadoc 注释转换为以 Java 表达式编写的可执行过程规范。在实证评估中,将 Javadoc 转换为过程规范时,Jdoctor 的精度达到 92%,召回率达到 83%。
我们还将 Jdoctor 衍生的规范提供给自动测试用例生成工具 Randoop。规范使 Randoop 能够生成测试案例,从而减少误报并揭示更多缺陷。
程序规范表达了预期的程序行为,因此可以启用或自动化许多软件工程任务。在软件测试中,它用作确定哪些输入合法和哪些输出正确的预言 [4, 17, 31, 37]。在调试中,它标识错误的语句 [29, 54]。在代码合成中,这是合成器致力于的目标 [28, 47]。在重构中,它确保转换是一致的 [23]。在形式验证中,它区分正确和错误的实现 [53]。在运行时监视中,它可以识别异常行为 [15]。自动化(部分)任务需要工具可以操纵的机器可读格式。正式的规范很好地达到了这个目的。但是,很少有正式的规范,因为编写规范不是常见的软件开发实践。
? 相比之下,非正式规范很容易以自然语言编写的半结构化和非结构化文档的形式提供。程序员在过程文档中指定前提条件、后置条件和特殊行为是标准做法。 Javadoc 标记语言和工具于 1995 年在 Java 的第一个版本中出现,而类似但跨语言的工具 Doxygen 在 2 年后出现了。 Java IDE 会自动插入 Javadoc 注释的模板。最重要的是,程序员已经习惯于编写这些注释。结果,大量代码包含了非正式的 Javadoc 规范。但是,软件工程工具很少使用这些非正式规范。
? 本文介绍了 Jdoctor,它是一种从程序员已经创建的工件(即 Javadoc 代码注释)自动构建可执行过程规范的技术,而无需程序员更改开发实践或做额外的工作。可执行规范是可以执行的规范,例如,因为它是用编程语言而不是其他某种逻辑编写的。它也需要在过程上表达,而不是(例如)声明性地要求某些值的存在而不指示如何计算它。由 Jdoctor 生成的过程规范可用于多种软件工程任务中,例如自动生成测试用例,如本文所示。
自动生成测试用例可以降低开发成本和软件故障的社会成本 [5, 27, 44]。要自动生成测试用例,测试生成器必须生成一个输入,该输入使被测程序执行某些操作,并生成一个 oracle 以确定程序是否正常运行。
? 创建准确的测试 Oracle 仍然是一个未解决的问题。正如我们现在所解释的,这将导致测试生成器同时遭受错误警报(当被测程序正确时测试失败)和错过警报(当被测程序有错误时测试通过)。例如,假设自动生成的测试中的方法调用引发了异常。抛出此异常并不一定意味着所测试的方法有错误。存在以下可能性:
(1)引发的异常实际上揭示了实现缺陷。一个示例是在主题程序中触发断言,或者以其他方式无法完成所请求的操作。
(2)抛出异常是预期的、期望的行为。一个示例是在不可变对象上调用变量时发生的IllegalOperationException。
.注释标记(<!--…-->)
语法: <!--注释内容-->
2.文件标记(<html>…</html>)
语法: <html>…</html>
说明:<html>这对标记是HTML文件的标记。<html>处于文件的最前面,表示HTML文件的开始。即浏览器从<html>标记开始解释,直到遇到</html>标记为止。
3.文件头标记(<head>…</head>)
语法: <head>…</head>
说明:
①由head这组标记定义的元素中,并不放置网页的任何内容,是放置关于这份HTML文件的信息。就是说,它并不属于HTML文件的主体,它包含文件的标题、编码方式和URL等。这些信息大部分用于提供索引、辨认或其他应用。
②这对标记在HTML文件中并不是必需的。如果某个HTML文件并不需要提供相关信息,则可省略<head>标记。
4.文件标题标记(<title>…</title>)
语法: <title>文件标题文字</title>
说明:此标记用于设定HTML文件的标题名称,它将显示在浏览器的标题栏中。
注意:<title>标记用于<head>标记中。但如果HTML文件中没有使用<head>标记,则<title>标记仍然起作用。
5.文件主体标记(<body>…</body>)
语法: <body>…</body>
说明:
①由<body>标记所建立的元素是HTML文件的内容主体,也是HTML文件的重点所在。HTML文件中要显示在网页上的所有内容,也都放置在这个元素中。
②<body>具有一些特殊的属性,可以设定背景及字符颜色等。
【注释】从技术上来说没有对错,理论上,你想怎么写就怎么写,你爱怎么写就怎么写!
但它确实也会对我们造成影响,尤其是在多人协同开发的系统中。杂乱的注释也会让你或你的队友头疼~
所以,我们需要规范一下注释。那什么才是好的注释呢?我们先来看看什么是不好的注释!
我们往往会写一段注释来说明“这是什么”。比如:
// Find all the users
let users=userHelper.findAll();
// Add score to each user
users.forEach((user)=> {
user.score++;
}
// Return the users
return users;
但是这段代码本身的意思就很清楚了,再附上注释就有点多余了。
所以我们应该将其剔除。
let users=userHelper.findAll();
users.forEach((user)=> {
user.score++;
}
return users;
那么,这段代码是不是就方便阅读了呢?其实,咱们还能更进一步:
let users=userHelper.findAll();
userHelper.incrementScoreForAll(users);
return users;
这样你感觉如何?相比于最开始的那段代码,这段是不是就看得舒舒服服?
所以,可读的代码比可读的注释更重要。优先考虑让你的代码说话,实在不行,再附上简短、清晰的注释。
// Find all users
let users=userHelper.findBanned();
// Give each user 100 extra score
users.forEach((user)=> {
user.score=0;
}
return users;
我们有时候会发现注释和代码并不匹配,比如这里为用户设置分数的操作。代码中是 0 分,注释却是 100 分。
导致出现这种情况有多种可能:
怎么办?让我们来看看优解:
// userHelper.js
function updateScoreForUsers(score, users) {
users.forEach((user)=> {
user.score +=score;
}
}
// Code 1: punish banned users
let users=userHelper.findBanned();
userHelper.updateScoreForUsers(users, -100);
return users;
// Code 2: give everybody 1 extra score
let users=userHelper.findAll();
userHelper.updateScoreForUsers(users, 1);
return users;
这样写将设置分数的逻辑封装成函数进行了抽离,功能更强了,也更易于阅读了。
现在,我们可以在多种情况下重复调用它,且不必担心注释未及时更新的问题了。
请问如果是这样的注释,你还有信心整个完整读下来吗?即使你是一个勇敢坚强的技术人,读下来也会消耗很多时间吧?这样低效率的事肯定不是我们想要的。
// userHelper.js
/**
* Mass updates the user score for the given a list of user
* The score will be updated by the amount given in the parameter score
* For example, if the parameter score is 5, the users will all receive 5 extra score
* But if the score is negative, it can also be used. In that case, the score will be decreased by 5.
* If you set score as 0, then this method will be useless as nothing will be updated.
* If you set the score as a non number value, the function will not do anything and return false
* just to ensure the score is not messed up after updating it with a non-number value
* Try to avoid using non-number values in the score parameter as this should not be used like that
* If you do however choose to use Infinity in the score argument, it will work, because Infinity is considered as a number in JavaScript
* If you set the score to Infinity, all the users score will become Inifinity, because n + Infinity where n is a number, will always result in Infinity
* Regarding the users, make sure this is an array! If it is not an array, we will not process the users score,
* then our method will simply return false instead and stop processing
* Also make sure the users array is a list of actual user objects, we do not check this, but make sure the object has all the required fields as expected
* especially the score object is important in this case.
* @returns {boolean} Returns true if successful, false if not processed.
*/
function updateScoreForUsers(score, users) {
if (isNaN(score) || typeof users !=='array') { return false; }
users.forEach((user)=> {
user.score +=score;
}
return true;
}
所以,请确保你的注释不要太长。有那么多想说的,可以写文档、可以写文章,不要写注释~
简单直接是最迷人的!
这是另一个极端的例子,但是它确实源自于现实的开发项目中。
// userHelper.js
/**
* Update score
* @returns {boolean} result
*/
function updateScoreForUsers(score, users) {
if (isNaN(score) || typeof users !=='array') { return false; }
users.forEach((user)=> {
user.score +=score;
}
return true;
}
此段代码注释只是说明了返回值,但是更为关键的传参并未作出释义。显得有些尴尬~
如果你决定注释,那就不要只写一半。请尽量准确、完整、干净的将其写出。从长期来看,你一定会从中受益。
好的注释就是告诉大家你为什么要进行注释!
比如:
// userHelper.js
function updateScoreForUsers(score, users) {
users.forEach((user)=> {
user.score +=score;
// VIPs are promised 500 extra score on top
if (user.type=='VIP') {
user.score +=500;
}
}
return true;
}
此例中我们可以明白 VIP 用户是被产品要求多加 500 分值的。这样其它开发就不会对此产生疑惑。
如果代码由多个团队维护,简单直接的小标注就更为必要了!
注释在代码中扮演很重要的角色。本瓜还记得大学老师说:注释应该占代码的三分之一。
我们都有不同的注释习惯,但是也应该有一个基本的指导:
代码可读就是最好的注释。
我是掘金安东尼: 一名人气前端技术博主(文章 100w+ 阅读量)
终身写作者(INFP 写作人格)
坚持与热爱(简书打卡 1000 日)
我能陪你一起度过漫长技术岁月吗(以梦为马)
觉得不错,给个三连吧(这是我最大的动力 )
*请认真填写需求信息,我们会在24小时内与您取得联系。