在这篇文章中,我重现了我在学习JUnit时使用的一种 "坏 "的编码方法,并将演示如何使用Sensei ,将 "坏 "的模式转换为商定的 "更好 "的编码模式。
当我在学习JUnit的时候,我只能在任何时候在我的脑海中保留这么多。我经常忘记如何在测试不工作时跳过它们。
如果我们在一个团队中工作,那么我们可以使用拉动请求的代码审查来帮助执行编码风格。当我们和一个更有经验的程序员结对编程时,我们可以缩短反馈周期。
我们也可以用工具来增强我们的流程,让工具来提示我们做正确的事情。Thoughtworks在他们的Technology Radar列表中把这描述为 "规则之上的工具", Sensei ,以便。"使做正确的事情变得容易,而不是应用类似检查表的治理规则和程序"
禁用一个JUnit测试
理想情况下,正如我们都知道的那样,我会使用@Disabled注解并写道。
@Disabled
@Test
void canWeAddTwoNumbers(){
Assertions.fail("this test was skipped and should not run");
}
但是,在学习时,我不得不训练自己使用@Disabled。
当我忘记如何禁用一个测试方法时,我会删除@Test注解,并重新命名测试。
class SkipThisTest {
void SKIPTHIScanWeAddTwoNumbers(){
Assertions.fail("this test was skipped and should not run");
}
}
这不是很好,但它完成了工作。我没有像Sensei 这样的东西来帮助我记忆,所以我陷入了使用不良的编码习惯。
我为这个职位承担的任务是:。
- 创建一个规则,通过重命名方法找到被 "跳过 "或 "禁用 "的方法。
- 创建一个QuickFix来重命名该方法,并添加一个@Test和@Disabled注解。
食谱设置
我使用Sensei 的第一步是 "添加新配方",并搜索我希望配方作用的编码模式。
名称。JUnit。从SKIPTHIS制作@Disabled @Test
简要描述。停止命名方法SKIPTHIS,使用@Disabled @Test代替。
而我的搜索非常简单。我使用一个基本的重词来匹配方法名称。
搜索:
方法:
名称:
匹配。"SKIPTHIS.*"
快速修复设置
QuickFix有点复杂,因为它将重写代码,我将用几个步骤来实现我的最终代码。
我想。
- 为方法添加@Test注解
- 给方法添加@Disabled注解
- 修改方法名称
使用addAnnotation修复添加注释是很简单的。如果我为注释使用一个完全合格的名称,那么Sensei 会自动为我添加导入。
availableFixes:
- name: "Add @Disabled and @Test Annotation"
actions:
- addAnnotation:
annotation:"@org.junit.jupiter.api.Test"
- addAnnotation:
annotation:"@org.junit.jupiter.api.Disabled"
实际的重命名似乎有点复杂,但我只是使用了一个regex替换,而用Sensei 的通用方法是在重写动作中使用sed。
因为重写动作是Mustache的模板,Sensei ,在模板机制上有一些功能扩展。一个函数用{{#...}}表示,所以对sed来说,函数是{{#sed}}。该函数需要两个逗号分隔的参数。
第一个参数是sed语句。
- s/(.*) SKIPTHIS(.*)/$1 $2/
第二个参数是应用sed语句的字符串,在本例中是方法本身,这在Mustache变量中表示为。
给我的改写行动的。
- 改写。
to: "{{#sed}}s/(.*) SKIPTHIS(.*)/$1 $2/,{{{.}}}{{/sed}}"
sed的实现要求,当参数本身包含逗号时,要用{{#encodeString}}和{{/encodeString}}来包裹它们。- 例如,{{#encodeString}}{{.}}}{{/encodeString}}。
反向配方
由于这是一个例子,而且我们可能想在演示中使用这个,我想探讨一下如何使用Sensei 配方来反推出上述变化。
通过思考,我想找到一个带有@Disabled注解的方法,但只在我做演示的SkipThisTest类中。
名称。JUnit: SkipThisTest中的演示,删除@Disabled,恢复为SKIPTHIS
简要说明:删除@Disabled,恢复为SKIPTHIS,用于项目中的演示目的。
级别:警告
配方设置搜索非常简单,在一个特定的类中匹配注释。
搜索:
方法:
注释:
类型。"Disabled"
in:
class:
name: "SkipThisTest"
为了避免使代码看起来像一个错误,我把配方上的一般设置定义为警告。警告在代码中以高亮显示,它不会使代码看起来像有大问题。
对于快速修复,由于我们已经匹配了方法,我使用重写动作,并使用变量填充模板。
availableFixes:
- name: "删除禁用并重命名为SKIPTHIS..."
actions:
- rewrite:
to: "{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
我添加了每个变量,除了修改器(因为我想摆脱注释),并将SKIPTHIS文本添加到模板中。
这个修复方法有一个弱点,即通过删除修改器,我也删除了任何其他的注释。
添加另一个行动
我可以添加另一个命名的修复程序,以便在使用alt+enter显示QuickFix时给我一个选择。
availableFixes:
- name: "删除禁用并重命名为SKIPTHIS..."
actions:
- rewrite:
to: "{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
target: "self"
- name: "Remove Disabled, keep other annotations, and rename to SKIPTHIS..."
actions:
- rewrite:
to: "{{#sed}}s/(@Disabled\n.*@Test)//,{{{ modifierList }}}{{/sed}}\n\
{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
target: "self"
在这里,我在新的快速修复中又增加了一行。
{{#sed}}s/(@Disabled\n.*@Test)//,{{修改器列表}}{{/sed}}。
这需要修改器列表,将其编码为一个字符串,然后使用sed从字符串中删除带有@Disabled的行,但保留修改器中的所有其他行,也就是说,它单独保留所有其他注释。
注意:记得在sed中加入",",否则你会看到在你的预览中加入一个注释。这就是Sensei ,提醒你在sed命令中的语法错误。
/* e.g: {{#sed}}s/all/world/,helloall{{/sed}} */
嵌套的sed调用
我很幸运,我可以在一次搜索和替换中同时匹配@Disabled和@Test。
如果代码比较复杂,我想有一连串的sed命令,那么我可以通过嵌套它们来实现。
{{#sed}}s/@Test//,{{#sed}}s/@Disabled\n//,{{{ modifierList }}}{{/sed}}{{/sed}}
在上面的例子中,我对{{修改器列表}}上应用@Test替换的结果进行了@Disabled替换。
摘要
sed是一种非常灵活的实现代码重写的方式,而且可以嵌套sed函数调用以实现复杂的重写条件。
像这样的配方最终往往是暂时的,因为我们用它们来改善我们的编程过程,一旦我们建立了肌肉记忆,不再使用不良的编程模式,我们就可以在Cookbook中删除或禁用它们。
---
你可以使用 "Preferences \ Plugins"(Mac)或 "Settings \ Plugins"(Windows)从IntelliJ内部安装Sensei ,然后搜索 "sensei secure code"。
这篇博文的所有代码都可以在GitHub上的`junitexamples`模块中找到,该模块是我们的博客实例库。 https://github.com/SecureCodeWarrior/sensei-blog-examples