利用个人编程过程改进Sensei

发表于2020年12月7日
作者:Alan Richardson
案例研究

利用个人编程过程改进Sensei

发表于2020年12月7日
作者:Alan Richardson
查看资源
查看资源

在这篇文章中,我重现了我在学习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

查看资源
查看资源

作者

艾伦-理查德森

想要更多吗?

在博客上深入了解我们最新的安全编码见解。

我们广泛的资源库旨在增强人类对安全编码技术提升的方法。

查看博客
想要更多吗?

获取关于开发者驱动的安全的最新研究

我们广泛的资源库充满了有用的资源,从白皮书到网络研讨会,让你开始使用开发者驱动的安全编码。现在就去探索它。

资源中心

利用个人编程过程改进Sensei

发表于2020年12月7日
作者:Alan Richardson

在这篇文章中,我重现了我在学习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

我们希望得到您的许可,向您发送有关我们产品和/或相关安全编码主题的信息。我们将始终以最谨慎的态度对待您的个人资料,绝不会将其出售给其他公司用于营销目的。

提交
要提交表格,请启用 "分析 "cookies。完成后,请随时再次禁用它们。