Mejora del proceso de programación personal mediante Sensei
Para este post, he recreado un enfoque de codificación "malo" que utilicé cuando estaba aprendiendo JUnit, y demostraré cómo convertir el patrón "malo" en un patrón de codificación acordado, y "mejor", utilizando Sensei.
Cuando estaba aprendiendo JUnit, sólo podía retener una cantidad de cosas en mi cabeza en un momento dado. Constantemente olvidaba cómo omitir las pruebas cuando no funcionaban.
Si trabajamos en equipo, podemos utilizar las revisiones de código en los pull requests para ayudar a reforzar los estilos de codificación. Y podemos acortar el ciclo de retroalimentación cuando programamos en pareja con un programador más experimentado.
También podemos aumentar nuestro proceso con herramientas y hacer que éstas nos indiquen que hagamos lo correcto. Thoughtworks lo describió como "herramientas en lugar de reglas", en su lista de Technology Radar para Sensei, para: "facilitar que se haga lo correcto en lugar de aplicar normas y procedimientos de gobernanza tipo lista de control"
Desactivación de una prueba JUnit
Lo ideal sería, como todos sabemos, utilizar la anotación @Disabled y escribir:
@Disabled
@Test
void canWeAddTwoNumbers(){
Assertions.fail("this test was skipped and should not run");
}
Pero, al aprender, tuve que entrenarme para usar @Disabled.
Cuando me olvidaba de cómo desactivar un método de prueba, eliminaba la anotación @Test y cambiaba el nombre de la prueba:
class SkipThisTest {
void SKIPTHIScanWeAddTwoNumbers(){
Assertions.fail("this test was skipped and should not run");
}
}
No era bueno, pero hacía el trabajo. No tenía algo como Sensei para ayudarme a recordar y entonces caí en el uso de patrones de codificación pobres.
Las tareas que he asumido para este puesto son:
- Cree una regla que encuentre los métodos que han sido "omitidos" o "deshabilitados" cambiando el nombre del método.
- Crea un QuickFix para renombrar el método y añadir una anotación @Test y @Disabled.
Ajustes de la receta
El primer paso que doy con Sensei es "añadir nueva receta" y buscar el patrón de codificación sobre el que quiero que actúe la receta.
Nombre: JUnit: Hacer @Disabled @Test de SKIPTHIS
Descripción breve: Deje de nombrar los métodos SKIPTHIS, utilice en su lugar @Disabled @Test
Y mi búsqueda es muy sencilla. Utilizo una regex básica para que coincida con el nombre del método.
búsqueda:
método:
nombre:
coincide: "SKIPTHIS.*"

Ajustes de QuickFix
El QuickFix es un poco más complicado porque va a reescribir el código, y voy a utilizar algunos pasos para lograr mi código final.
Quiero hacerlo:
- añadir una anotación @Test al método
- añadir una anotación @Disabled al método
- modificar el nombre del método
Añadir las anotaciones es bastante simple usando el arreglo addAnnotation. Si utilizo un nombre completo para la anotación, Sensei añadirá automáticamente las importaciones por mí.
availableFixes:
- name: "Add @Disabled and @Test Annotation"
acciones:
- addAnnotation:
annotation: "@org.junit.jupiter.api.Test"
- addAnnotation:
annotation: "@org.junit.jupiter.api.Disabled"
El renombramiento real parece un poco más complicado, pero sólo estoy usando un reemplazo regex, y la forma genérica de hacer esto con Sensei es usar sed en una acción de reescritura.
Como las acciones de reescritura son plantillas de Mustache, Sensei tiene algunas extensiones funcionales en el mecanismo de plantillas. Una función se representa con {{#...}} así que para sed la función es {{#sed}}. La función toma dos argumentos separados por comas.
El primer argumento es la declaración sed:
- s/(.*) SKIPTHIS(.*)/$1 $2/
El segundo argumento es el String al que aplicar la sentencia sed, que en este caso es el propio método, y que se representa en las variables Mustache como:
- {{{.}}}
Dándome la acción de reescribir:
- Reescritura:
to: "{{#sed}}s/(.*) SKIPTHIS(.*)/$1 $2/,{{{.}}}{{/sed}}"

La implementación de sed requiere que cuando los argumentos mismos contengan comas, se envuelvan con {{#encodeString}} y {{/encodeString}} - Por ejemplo, {{#encodeString}}{{{.}}}{{/encodeString}}
Receta inversa
Dado que se trata de un ejemplo, y es posible que queramos utilizarlo en demostraciones, quería explorar cómo revertir el cambio anterior utilizando una receta de Sensei .
Pensando bien quiero encontrar un método anotado con @Disabled pero sólo en la clase SkipThisTest donde hago la demostración:
Nombre: JUnit: demo en SkipThisTest eliminar @Disabled y volver a SKIPTHIS
Descripción breve: eliminar @Disabled y volver a SKIPTHIS para fines de demostración en el proyecto
Nivel: advertencia
La búsqueda de configuraciones de recetas es muy simple, ya que coincide con la anotación en una clase específica.
búsqueda:
método:
anotación:
tipo: "Disabled"
in:
class:
name: "SkipThisTest"
Para evitar que el código se vea como un error, definí la configuración general de la receta como una Advertencia. Las advertencias se muestran con resaltados en el código y no hace que el código parezca que tiene un problema mayor.
Para el Quick fix, ya que hemos emparejado el método, utilizo la acción de reescritura y relleno la plantilla utilizando las variables.
availableFixes:
- name: "Eliminar Desactivado y cambiar el nombre a SKIPTHIS..."
actions:
- rewrite:
to: "{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
Agrego todas las variables excepto el modificador (ya que quiero deshacerme de las anotaciones) y añado el texto SKIPTHIS en la plantilla.
Este arreglo tiene la debilidad de que al eliminar los modificadores, elimino también cualquier otra anotación.
Añadir otra acción
Puedo añadir otro arreglo con nombre, para que me dé una opción cuando se use el alt+enter para mostrar el QuickFix.
availableFixes:
- name: "Eliminar Desactivado y cambiar el nombre a 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"
Aquí, he añadido una línea adicional en el nuevo Quick Fix.
{{sed}}s/(@Disabled\n.*@Test)//,{{modifierList}} {{sed}}
Esto toma la lista de modificadores, la codifica como una cadena, luego utiliza sed para eliminar la línea con @Disabled de la cadena, pero deja todas las demás líneas del modificador, es decir, deja todas las demás anotaciones.
NOTA: Recuerde añadir el "," en el sed, de lo contrario verá un comentario añadido a su vista previa. Así es como Sensei le avisa de los errores de sintaxis en el comando sed.
/* e.g: {{#sed}}s/all/world/,helloall{{/sed}} */
Llamadas sed anidadas
Tuve la suerte de poder coincidir con @Disabled y @Test en una sola búsqueda y reemplazo.
Si el código es más complicado y quiero tener una secuencia de comandos sed entonces puedo hacerlo anidando:
{{#sed}}s/@Test//,{{#sed}}s/@Disabled\n//,{{{ modifierList }}}{{/sed}}{{/sed}}
En el ejemplo anterior, aplico el reemplazo @Test a los resultados de aplicar el reemplazo @Disabled en el {{{ modifierList }}}.
Resumen
sed es una forma muy flexible de lograr la reescritura de código y es posible anidar las llamadas a la función sed para obtener condiciones de reescritura complicadas.
Este tipo de recetas suelen ser temporales porque las utilizamos para mejorar nuestro proceso de programación, y una vez que hayamos creado la memoria muscular y ya no utilicemos el mal patrón de programación podemos eliminarlo o desactivarlo en el Libro de Cocina.
---
Puedes instalar Sensei desde IntelliJ usando "Preferences \ Plugins" (Mac) o "Settings \ Plugins" (Windows) y luego sólo busca "sensei secure code".
Todo el código de esta entrada del blog se puede encontrar en GitHub en el módulo `junitexamples` de nuestro repositorio de ejemplos del blog https://github.com/SecureCodeWarrior/sensei-blog-examples


Aprenda a utilizar las revisiones de código en las solicitudes de extracción para ayudar a reforzar los estilos de codificación. Y acortar el ciclo de retroalimentación al programar en pareja con un programador más experimentado.
Alan Richardson cuenta con más de veinte años de experiencia profesional en TI, trabajando como desarrollador y en todos los niveles de la jerarquía de pruebas, desde probador hasta jefe de pruebas. Jefe de Relaciones con los Desarrolladores en Secure Code Warrior, trabaja directamente con los equipos, para mejorar el desarrollo de un código seguro de calidad. Alan es autor de cuatro libros, entre ellos "Dear Evil Tester" y "Java For Testers". Alan también ha creado una formación en línea courses para ayudar a la gente a aprender las pruebas técnicas de la web y Selenium WebDriver con Java. Alan publica sus escritos y vídeos de formación en SeleniumSimplified.com, EvilTester.com, JavaForTesters.com, y CompendiumDev.co.uk.

Secure Code Warrior está a disposición de su organización para ayudarle a proteger el código a lo largo de todo el ciclo de vida de desarrollo de software y crear una cultura en la que la ciberseguridad sea una prioridad. Tanto si es director de AppSec, desarrollador, CISO o cualquier persona implicada en la seguridad, podemos ayudar a su organización a reducir los riesgos asociados a un código inseguro.
Reservar una demostraciónAlan Richardson cuenta con más de veinte años de experiencia profesional en TI, trabajando como desarrollador y en todos los niveles de la jerarquía de pruebas, desde probador hasta jefe de pruebas. Jefe de Relaciones con los Desarrolladores en Secure Code Warrior, trabaja directamente con los equipos, para mejorar el desarrollo de un código seguro de calidad. Alan es autor de cuatro libros, entre ellos "Dear Evil Tester" y "Java For Testers". Alan también ha creado una formación en línea courses para ayudar a la gente a aprender las pruebas técnicas de la web y Selenium WebDriver con Java. Alan publica sus escritos y vídeos de formación en SeleniumSimplified.com, EvilTester.com, JavaForTesters.com, y CompendiumDev.co.uk.


Para este post, he recreado un enfoque de codificación "malo" que utilicé cuando estaba aprendiendo JUnit, y demostraré cómo convertir el patrón "malo" en un patrón de codificación acordado, y "mejor", utilizando Sensei.
Cuando estaba aprendiendo JUnit, sólo podía retener una cantidad de cosas en mi cabeza en un momento dado. Constantemente olvidaba cómo omitir las pruebas cuando no funcionaban.
Si trabajamos en equipo, podemos utilizar las revisiones de código en los pull requests para ayudar a reforzar los estilos de codificación. Y podemos acortar el ciclo de retroalimentación cuando programamos en pareja con un programador más experimentado.
También podemos aumentar nuestro proceso con herramientas y hacer que éstas nos indiquen que hagamos lo correcto. Thoughtworks lo describió como "herramientas en lugar de reglas", en su lista de Technology Radar para Sensei, para: "facilitar que se haga lo correcto en lugar de aplicar normas y procedimientos de gobernanza tipo lista de control"
Desactivación de una prueba JUnit
Lo ideal sería, como todos sabemos, utilizar la anotación @Disabled y escribir:
@Disabled
@Test
void canWeAddTwoNumbers(){
Assertions.fail("this test was skipped and should not run");
}
Pero, al aprender, tuve que entrenarme para usar @Disabled.
Cuando me olvidaba de cómo desactivar un método de prueba, eliminaba la anotación @Test y cambiaba el nombre de la prueba:
class SkipThisTest {
void SKIPTHIScanWeAddTwoNumbers(){
Assertions.fail("this test was skipped and should not run");
}
}
No era bueno, pero hacía el trabajo. No tenía algo como Sensei para ayudarme a recordar y entonces caí en el uso de patrones de codificación pobres.
Las tareas que he asumido para este puesto son:
- Cree una regla que encuentre los métodos que han sido "omitidos" o "deshabilitados" cambiando el nombre del método.
- Crea un QuickFix para renombrar el método y añadir una anotación @Test y @Disabled.
Ajustes de la receta
El primer paso que doy con Sensei es "añadir nueva receta" y buscar el patrón de codificación sobre el que quiero que actúe la receta.
Nombre: JUnit: Hacer @Disabled @Test de SKIPTHIS
Descripción breve: Deje de nombrar los métodos SKIPTHIS, utilice en su lugar @Disabled @Test
Y mi búsqueda es muy sencilla. Utilizo una regex básica para que coincida con el nombre del método.
búsqueda:
método:
nombre:
coincide: "SKIPTHIS.*"

Ajustes de QuickFix
El QuickFix es un poco más complicado porque va a reescribir el código, y voy a utilizar algunos pasos para lograr mi código final.
Quiero hacerlo:
- añadir una anotación @Test al método
- añadir una anotación @Disabled al método
- modificar el nombre del método
Añadir las anotaciones es bastante simple usando el arreglo addAnnotation. Si utilizo un nombre completo para la anotación, Sensei añadirá automáticamente las importaciones por mí.
availableFixes:
- name: "Add @Disabled and @Test Annotation"
acciones:
- addAnnotation:
annotation: "@org.junit.jupiter.api.Test"
- addAnnotation:
annotation: "@org.junit.jupiter.api.Disabled"
El renombramiento real parece un poco más complicado, pero sólo estoy usando un reemplazo regex, y la forma genérica de hacer esto con Sensei es usar sed en una acción de reescritura.
Como las acciones de reescritura son plantillas de Mustache, Sensei tiene algunas extensiones funcionales en el mecanismo de plantillas. Una función se representa con {{#...}} así que para sed la función es {{#sed}}. La función toma dos argumentos separados por comas.
El primer argumento es la declaración sed:
- s/(.*) SKIPTHIS(.*)/$1 $2/
El segundo argumento es el String al que aplicar la sentencia sed, que en este caso es el propio método, y que se representa en las variables Mustache como:
- {{{.}}}
Dándome la acción de reescribir:
- Reescritura:
to: "{{#sed}}s/(.*) SKIPTHIS(.*)/$1 $2/,{{{.}}}{{/sed}}"

La implementación de sed requiere que cuando los argumentos mismos contengan comas, se envuelvan con {{#encodeString}} y {{/encodeString}} - Por ejemplo, {{#encodeString}}{{{.}}}{{/encodeString}}
Receta inversa
Dado que se trata de un ejemplo, y es posible que queramos utilizarlo en demostraciones, quería explorar cómo revertir el cambio anterior utilizando una receta de Sensei .
Pensando bien quiero encontrar un método anotado con @Disabled pero sólo en la clase SkipThisTest donde hago la demostración:
Nombre: JUnit: demo en SkipThisTest eliminar @Disabled y volver a SKIPTHIS
Descripción breve: eliminar @Disabled y volver a SKIPTHIS para fines de demostración en el proyecto
Nivel: advertencia
La búsqueda de configuraciones de recetas es muy simple, ya que coincide con la anotación en una clase específica.
búsqueda:
método:
anotación:
tipo: "Disabled"
in:
class:
name: "SkipThisTest"
Para evitar que el código se vea como un error, definí la configuración general de la receta como una Advertencia. Las advertencias se muestran con resaltados en el código y no hace que el código parezca que tiene un problema mayor.
Para el Quick fix, ya que hemos emparejado el método, utilizo la acción de reescritura y relleno la plantilla utilizando las variables.
availableFixes:
- name: "Eliminar Desactivado y cambiar el nombre a SKIPTHIS..."
actions:
- rewrite:
to: "{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
Agrego todas las variables excepto el modificador (ya que quiero deshacerme de las anotaciones) y añado el texto SKIPTHIS en la plantilla.
Este arreglo tiene la debilidad de que al eliminar los modificadores, elimino también cualquier otra anotación.
Añadir otra acción
Puedo añadir otro arreglo con nombre, para que me dé una opción cuando se use el alt+enter para mostrar el QuickFix.
availableFixes:
- name: "Eliminar Desactivado y cambiar el nombre a 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"
Aquí, he añadido una línea adicional en el nuevo Quick Fix.
{{sed}}s/(@Disabled\n.*@Test)//,{{modifierList}} {{sed}}
Esto toma la lista de modificadores, la codifica como una cadena, luego utiliza sed para eliminar la línea con @Disabled de la cadena, pero deja todas las demás líneas del modificador, es decir, deja todas las demás anotaciones.
NOTA: Recuerde añadir el "," en el sed, de lo contrario verá un comentario añadido a su vista previa. Así es como Sensei le avisa de los errores de sintaxis en el comando sed.
/* e.g: {{#sed}}s/all/world/,helloall{{/sed}} */
Llamadas sed anidadas
Tuve la suerte de poder coincidir con @Disabled y @Test en una sola búsqueda y reemplazo.
Si el código es más complicado y quiero tener una secuencia de comandos sed entonces puedo hacerlo anidando:
{{#sed}}s/@Test//,{{#sed}}s/@Disabled\n//,{{{ modifierList }}}{{/sed}}{{/sed}}
En el ejemplo anterior, aplico el reemplazo @Test a los resultados de aplicar el reemplazo @Disabled en el {{{ modifierList }}}.
Resumen
sed es una forma muy flexible de lograr la reescritura de código y es posible anidar las llamadas a la función sed para obtener condiciones de reescritura complicadas.
Este tipo de recetas suelen ser temporales porque las utilizamos para mejorar nuestro proceso de programación, y una vez que hayamos creado la memoria muscular y ya no utilicemos el mal patrón de programación podemos eliminarlo o desactivarlo en el Libro de Cocina.
---
Puedes instalar Sensei desde IntelliJ usando "Preferences \ Plugins" (Mac) o "Settings \ Plugins" (Windows) y luego sólo busca "sensei secure code".
Todo el código de esta entrada del blog se puede encontrar en GitHub en el módulo `junitexamples` de nuestro repositorio de ejemplos del blog https://github.com/SecureCodeWarrior/sensei-blog-examples

Para este post, he recreado un enfoque de codificación "malo" que utilicé cuando estaba aprendiendo JUnit, y demostraré cómo convertir el patrón "malo" en un patrón de codificación acordado, y "mejor", utilizando Sensei.
Cuando estaba aprendiendo JUnit, sólo podía retener una cantidad de cosas en mi cabeza en un momento dado. Constantemente olvidaba cómo omitir las pruebas cuando no funcionaban.
Si trabajamos en equipo, podemos utilizar las revisiones de código en los pull requests para ayudar a reforzar los estilos de codificación. Y podemos acortar el ciclo de retroalimentación cuando programamos en pareja con un programador más experimentado.
También podemos aumentar nuestro proceso con herramientas y hacer que éstas nos indiquen que hagamos lo correcto. Thoughtworks lo describió como "herramientas en lugar de reglas", en su lista de Technology Radar para Sensei, para: "facilitar que se haga lo correcto en lugar de aplicar normas y procedimientos de gobernanza tipo lista de control"
Desactivación de una prueba JUnit
Lo ideal sería, como todos sabemos, utilizar la anotación @Disabled y escribir:
@Disabled
@Test
void canWeAddTwoNumbers(){
Assertions.fail("this test was skipped and should not run");
}
Pero, al aprender, tuve que entrenarme para usar @Disabled.
Cuando me olvidaba de cómo desactivar un método de prueba, eliminaba la anotación @Test y cambiaba el nombre de la prueba:
class SkipThisTest {
void SKIPTHIScanWeAddTwoNumbers(){
Assertions.fail("this test was skipped and should not run");
}
}
No era bueno, pero hacía el trabajo. No tenía algo como Sensei para ayudarme a recordar y entonces caí en el uso de patrones de codificación pobres.
Las tareas que he asumido para este puesto son:
- Cree una regla que encuentre los métodos que han sido "omitidos" o "deshabilitados" cambiando el nombre del método.
- Crea un QuickFix para renombrar el método y añadir una anotación @Test y @Disabled.
Ajustes de la receta
El primer paso que doy con Sensei es "añadir nueva receta" y buscar el patrón de codificación sobre el que quiero que actúe la receta.
Nombre: JUnit: Hacer @Disabled @Test de SKIPTHIS
Descripción breve: Deje de nombrar los métodos SKIPTHIS, utilice en su lugar @Disabled @Test
Y mi búsqueda es muy sencilla. Utilizo una regex básica para que coincida con el nombre del método.
búsqueda:
método:
nombre:
coincide: "SKIPTHIS.*"

Ajustes de QuickFix
El QuickFix es un poco más complicado porque va a reescribir el código, y voy a utilizar algunos pasos para lograr mi código final.
Quiero hacerlo:
- añadir una anotación @Test al método
- añadir una anotación @Disabled al método
- modificar el nombre del método
Añadir las anotaciones es bastante simple usando el arreglo addAnnotation. Si utilizo un nombre completo para la anotación, Sensei añadirá automáticamente las importaciones por mí.
availableFixes:
- name: "Add @Disabled and @Test Annotation"
acciones:
- addAnnotation:
annotation: "@org.junit.jupiter.api.Test"
- addAnnotation:
annotation: "@org.junit.jupiter.api.Disabled"
El renombramiento real parece un poco más complicado, pero sólo estoy usando un reemplazo regex, y la forma genérica de hacer esto con Sensei es usar sed en una acción de reescritura.
Como las acciones de reescritura son plantillas de Mustache, Sensei tiene algunas extensiones funcionales en el mecanismo de plantillas. Una función se representa con {{#...}} así que para sed la función es {{#sed}}. La función toma dos argumentos separados por comas.
El primer argumento es la declaración sed:
- s/(.*) SKIPTHIS(.*)/$1 $2/
El segundo argumento es el String al que aplicar la sentencia sed, que en este caso es el propio método, y que se representa en las variables Mustache como:
- {{{.}}}
Dándome la acción de reescribir:
- Reescritura:
to: "{{#sed}}s/(.*) SKIPTHIS(.*)/$1 $2/,{{{.}}}{{/sed}}"

La implementación de sed requiere que cuando los argumentos mismos contengan comas, se envuelvan con {{#encodeString}} y {{/encodeString}} - Por ejemplo, {{#encodeString}}{{{.}}}{{/encodeString}}
Receta inversa
Dado que se trata de un ejemplo, y es posible que queramos utilizarlo en demostraciones, quería explorar cómo revertir el cambio anterior utilizando una receta de Sensei .
Pensando bien quiero encontrar un método anotado con @Disabled pero sólo en la clase SkipThisTest donde hago la demostración:
Nombre: JUnit: demo en SkipThisTest eliminar @Disabled y volver a SKIPTHIS
Descripción breve: eliminar @Disabled y volver a SKIPTHIS para fines de demostración en el proyecto
Nivel: advertencia
La búsqueda de configuraciones de recetas es muy simple, ya que coincide con la anotación en una clase específica.
búsqueda:
método:
anotación:
tipo: "Disabled"
in:
class:
name: "SkipThisTest"
Para evitar que el código se vea como un error, definí la configuración general de la receta como una Advertencia. Las advertencias se muestran con resaltados en el código y no hace que el código parezca que tiene un problema mayor.
Para el Quick fix, ya que hemos emparejado el método, utilizo la acción de reescritura y relleno la plantilla utilizando las variables.
availableFixes:
- name: "Eliminar Desactivado y cambiar el nombre a SKIPTHIS..."
actions:
- rewrite:
to: "{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
Agrego todas las variables excepto el modificador (ya que quiero deshacerme de las anotaciones) y añado el texto SKIPTHIS en la plantilla.
Este arreglo tiene la debilidad de que al eliminar los modificadores, elimino también cualquier otra anotación.
Añadir otra acción
Puedo añadir otro arreglo con nombre, para que me dé una opción cuando se use el alt+enter para mostrar el QuickFix.
availableFixes:
- name: "Eliminar Desactivado y cambiar el nombre a 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"
Aquí, he añadido una línea adicional en el nuevo Quick Fix.
{{sed}}s/(@Disabled\n.*@Test)//,{{modifierList}} {{sed}}
Esto toma la lista de modificadores, la codifica como una cadena, luego utiliza sed para eliminar la línea con @Disabled de la cadena, pero deja todas las demás líneas del modificador, es decir, deja todas las demás anotaciones.
NOTA: Recuerde añadir el "," en el sed, de lo contrario verá un comentario añadido a su vista previa. Así es como Sensei le avisa de los errores de sintaxis en el comando sed.
/* e.g: {{#sed}}s/all/world/,helloall{{/sed}} */
Llamadas sed anidadas
Tuve la suerte de poder coincidir con @Disabled y @Test en una sola búsqueda y reemplazo.
Si el código es más complicado y quiero tener una secuencia de comandos sed entonces puedo hacerlo anidando:
{{#sed}}s/@Test//,{{#sed}}s/@Disabled\n//,{{{ modifierList }}}{{/sed}}{{/sed}}
En el ejemplo anterior, aplico el reemplazo @Test a los resultados de aplicar el reemplazo @Disabled en el {{{ modifierList }}}.
Resumen
sed es una forma muy flexible de lograr la reescritura de código y es posible anidar las llamadas a la función sed para obtener condiciones de reescritura complicadas.
Este tipo de recetas suelen ser temporales porque las utilizamos para mejorar nuestro proceso de programación, y una vez que hayamos creado la memoria muscular y ya no utilicemos el mal patrón de programación podemos eliminarlo o desactivarlo en el Libro de Cocina.
---
Puedes instalar Sensei desde IntelliJ usando "Preferences \ Plugins" (Mac) o "Settings \ Plugins" (Windows) y luego sólo busca "sensei secure code".
Todo el código de esta entrada del blog se puede encontrar en GitHub en el módulo `junitexamples` de nuestro repositorio de ejemplos del blog https://github.com/SecureCodeWarrior/sensei-blog-examples

Haga clic en el siguiente enlace y descargue el PDF de este recurso.
Secure Code Warrior está a disposición de su organización para ayudarle a proteger el código a lo largo de todo el ciclo de vida de desarrollo de software y crear una cultura en la que la ciberseguridad sea una prioridad. Tanto si es director de AppSec, desarrollador, CISO o cualquier persona implicada en la seguridad, podemos ayudar a su organización a reducir los riesgos asociados a un código inseguro.
Ver el informeReservar una demostraciónAlan Richardson cuenta con más de veinte años de experiencia profesional en TI, trabajando como desarrollador y en todos los niveles de la jerarquía de pruebas, desde probador hasta jefe de pruebas. Jefe de Relaciones con los Desarrolladores en Secure Code Warrior, trabaja directamente con los equipos, para mejorar el desarrollo de un código seguro de calidad. Alan es autor de cuatro libros, entre ellos "Dear Evil Tester" y "Java For Testers". Alan también ha creado una formación en línea courses para ayudar a la gente a aprender las pruebas técnicas de la web y Selenium WebDriver con Java. Alan publica sus escritos y vídeos de formación en SeleniumSimplified.com, EvilTester.com, JavaForTesters.com, y CompendiumDev.co.uk.
Para este post, he recreado un enfoque de codificación "malo" que utilicé cuando estaba aprendiendo JUnit, y demostraré cómo convertir el patrón "malo" en un patrón de codificación acordado, y "mejor", utilizando Sensei.
Cuando estaba aprendiendo JUnit, sólo podía retener una cantidad de cosas en mi cabeza en un momento dado. Constantemente olvidaba cómo omitir las pruebas cuando no funcionaban.
Si trabajamos en equipo, podemos utilizar las revisiones de código en los pull requests para ayudar a reforzar los estilos de codificación. Y podemos acortar el ciclo de retroalimentación cuando programamos en pareja con un programador más experimentado.
También podemos aumentar nuestro proceso con herramientas y hacer que éstas nos indiquen que hagamos lo correcto. Thoughtworks lo describió como "herramientas en lugar de reglas", en su lista de Technology Radar para Sensei, para: "facilitar que se haga lo correcto en lugar de aplicar normas y procedimientos de gobernanza tipo lista de control"
Desactivación de una prueba JUnit
Lo ideal sería, como todos sabemos, utilizar la anotación @Disabled y escribir:
@Disabled
@Test
void canWeAddTwoNumbers(){
Assertions.fail("this test was skipped and should not run");
}
Pero, al aprender, tuve que entrenarme para usar @Disabled.
Cuando me olvidaba de cómo desactivar un método de prueba, eliminaba la anotación @Test y cambiaba el nombre de la prueba:
class SkipThisTest {
void SKIPTHIScanWeAddTwoNumbers(){
Assertions.fail("this test was skipped and should not run");
}
}
No era bueno, pero hacía el trabajo. No tenía algo como Sensei para ayudarme a recordar y entonces caí en el uso de patrones de codificación pobres.
Las tareas que he asumido para este puesto son:
- Cree una regla que encuentre los métodos que han sido "omitidos" o "deshabilitados" cambiando el nombre del método.
- Crea un QuickFix para renombrar el método y añadir una anotación @Test y @Disabled.
Ajustes de la receta
El primer paso que doy con Sensei es "añadir nueva receta" y buscar el patrón de codificación sobre el que quiero que actúe la receta.
Nombre: JUnit: Hacer @Disabled @Test de SKIPTHIS
Descripción breve: Deje de nombrar los métodos SKIPTHIS, utilice en su lugar @Disabled @Test
Y mi búsqueda es muy sencilla. Utilizo una regex básica para que coincida con el nombre del método.
búsqueda:
método:
nombre:
coincide: "SKIPTHIS.*"

Ajustes de QuickFix
El QuickFix es un poco más complicado porque va a reescribir el código, y voy a utilizar algunos pasos para lograr mi código final.
Quiero hacerlo:
- añadir una anotación @Test al método
- añadir una anotación @Disabled al método
- modificar el nombre del método
Añadir las anotaciones es bastante simple usando el arreglo addAnnotation. Si utilizo un nombre completo para la anotación, Sensei añadirá automáticamente las importaciones por mí.
availableFixes:
- name: "Add @Disabled and @Test Annotation"
acciones:
- addAnnotation:
annotation: "@org.junit.jupiter.api.Test"
- addAnnotation:
annotation: "@org.junit.jupiter.api.Disabled"
El renombramiento real parece un poco más complicado, pero sólo estoy usando un reemplazo regex, y la forma genérica de hacer esto con Sensei es usar sed en una acción de reescritura.
Como las acciones de reescritura son plantillas de Mustache, Sensei tiene algunas extensiones funcionales en el mecanismo de plantillas. Una función se representa con {{#...}} así que para sed la función es {{#sed}}. La función toma dos argumentos separados por comas.
El primer argumento es la declaración sed:
- s/(.*) SKIPTHIS(.*)/$1 $2/
El segundo argumento es el String al que aplicar la sentencia sed, que en este caso es el propio método, y que se representa en las variables Mustache como:
- {{{.}}}
Dándome la acción de reescribir:
- Reescritura:
to: "{{#sed}}s/(.*) SKIPTHIS(.*)/$1 $2/,{{{.}}}{{/sed}}"

La implementación de sed requiere que cuando los argumentos mismos contengan comas, se envuelvan con {{#encodeString}} y {{/encodeString}} - Por ejemplo, {{#encodeString}}{{{.}}}{{/encodeString}}
Receta inversa
Dado que se trata de un ejemplo, y es posible que queramos utilizarlo en demostraciones, quería explorar cómo revertir el cambio anterior utilizando una receta de Sensei .
Pensando bien quiero encontrar un método anotado con @Disabled pero sólo en la clase SkipThisTest donde hago la demostración:
Nombre: JUnit: demo en SkipThisTest eliminar @Disabled y volver a SKIPTHIS
Descripción breve: eliminar @Disabled y volver a SKIPTHIS para fines de demostración en el proyecto
Nivel: advertencia
La búsqueda de configuraciones de recetas es muy simple, ya que coincide con la anotación en una clase específica.
búsqueda:
método:
anotación:
tipo: "Disabled"
in:
class:
name: "SkipThisTest"
Para evitar que el código se vea como un error, definí la configuración general de la receta como una Advertencia. Las advertencias se muestran con resaltados en el código y no hace que el código parezca que tiene un problema mayor.
Para el Quick fix, ya que hemos emparejado el método, utilizo la acción de reescritura y relleno la plantilla utilizando las variables.
availableFixes:
- name: "Eliminar Desactivado y cambiar el nombre a SKIPTHIS..."
actions:
- rewrite:
to: "{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
Agrego todas las variables excepto el modificador (ya que quiero deshacerme de las anotaciones) y añado el texto SKIPTHIS en la plantilla.
Este arreglo tiene la debilidad de que al eliminar los modificadores, elimino también cualquier otra anotación.
Añadir otra acción
Puedo añadir otro arreglo con nombre, para que me dé una opción cuando se use el alt+enter para mostrar el QuickFix.
availableFixes:
- name: "Eliminar Desactivado y cambiar el nombre a 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"
Aquí, he añadido una línea adicional en el nuevo Quick Fix.
{{sed}}s/(@Disabled\n.*@Test)//,{{modifierList}} {{sed}}
Esto toma la lista de modificadores, la codifica como una cadena, luego utiliza sed para eliminar la línea con @Disabled de la cadena, pero deja todas las demás líneas del modificador, es decir, deja todas las demás anotaciones.
NOTA: Recuerde añadir el "," en el sed, de lo contrario verá un comentario añadido a su vista previa. Así es como Sensei le avisa de los errores de sintaxis en el comando sed.
/* e.g: {{#sed}}s/all/world/,helloall{{/sed}} */
Llamadas sed anidadas
Tuve la suerte de poder coincidir con @Disabled y @Test en una sola búsqueda y reemplazo.
Si el código es más complicado y quiero tener una secuencia de comandos sed entonces puedo hacerlo anidando:
{{#sed}}s/@Test//,{{#sed}}s/@Disabled\n//,{{{ modifierList }}}{{/sed}}{{/sed}}
En el ejemplo anterior, aplico el reemplazo @Test a los resultados de aplicar el reemplazo @Disabled en el {{{ modifierList }}}.
Resumen
sed es una forma muy flexible de lograr la reescritura de código y es posible anidar las llamadas a la función sed para obtener condiciones de reescritura complicadas.
Este tipo de recetas suelen ser temporales porque las utilizamos para mejorar nuestro proceso de programación, y una vez que hayamos creado la memoria muscular y ya no utilicemos el mal patrón de programación podemos eliminarlo o desactivarlo en el Libro de Cocina.
---
Puedes instalar Sensei desde IntelliJ usando "Preferences \ Plugins" (Mac) o "Settings \ Plugins" (Windows) y luego sólo busca "sensei secure code".
Todo el código de esta entrada del blog se puede encontrar en GitHub en el módulo `junitexamples` de nuestro repositorio de ejemplos del blog https://github.com/SecureCodeWarrior/sensei-blog-examples
Índice
Alan Richardson cuenta con más de veinte años de experiencia profesional en TI, trabajando como desarrollador y en todos los niveles de la jerarquía de pruebas, desde probador hasta jefe de pruebas. Jefe de Relaciones con los Desarrolladores en Secure Code Warrior, trabaja directamente con los equipos, para mejorar el desarrollo de un código seguro de calidad. Alan es autor de cuatro libros, entre ellos "Dear Evil Tester" y "Java For Testers". Alan también ha creado una formación en línea courses para ayudar a la gente a aprender las pruebas técnicas de la web y Selenium WebDriver con Java. Alan publica sus escritos y vídeos de formación en SeleniumSimplified.com, EvilTester.com, JavaForTesters.com, y CompendiumDev.co.uk.

Secure Code Warrior está a disposición de su organización para ayudarle a proteger el código a lo largo de todo el ciclo de vida de desarrollo de software y crear una cultura en la que la ciberseguridad sea una prioridad. Tanto si es director de AppSec, desarrollador, CISO o cualquier persona implicada en la seguridad, podemos ayudar a su organización a reducir los riesgos asociados a un código inseguro.
Reservar una demostraciónDescargarRecursos para empezar
Servicios profesionales - Acelerar con experiencia
El equipo de servicios de estrategia de programas (PSS) de Secure Code Warriorle ayuda a crear, mejorar y optimizar su programa de codificación segura. Tanto si empieza de cero como si está perfeccionando su enfoque, nuestros expertos le proporcionarán orientación personalizada.
Temas y contenidos de la formación sobre código seguro
Nuestro contenido, líder en el sector, evoluciona constantemente para adaptarse al cambiante panorama del desarrollo de software teniendo en cuenta su función. Temas que cubren todo, desde IA a XQuery Injection, ofrecidos para una variedad de roles desde Arquitectos e Ingenieros a Product Managers y QA. Eche un vistazo a lo que ofrece nuestro catálogo de contenidos por tema y función.
Búsqueda: Aprendizaje líder en la industria para mantener a los desarrolladores por delante mitigando el riesgo.
Quests es una learning platform que ayuda a los desarrolladores a mitigar los riesgos de seguridad del software mediante la mejora de sus habilidades de codificación segura. Con rutas de aprendizaje curadas, desafíos prácticos y actividades interactivas, capacita a los desarrolladores para identificar y prevenir vulnerabilidades.
Recursos para empezar
¿Vibe Coding va a convertir tu código en una fiesta de fraternidad?
Vibe Coding es como una fiesta de fraternidad universitaria, y la IA es la pieza central de todos los festejos, el barril. Es muy divertido dar rienda suelta a la creatividad y ver adónde te lleva tu imaginación, pero después de unas cuantas borracheras, beber (o usar IA) con moderación es, sin duda, la solución más segura a largo plazo.
La Década de los Defensores: Secure Code Warrior Cumple Diez Años
Secure Code Warriorha permanecido unido, dirigiendo el barco a través de cada lección, triunfo y contratiempo durante toda una década. Estamos creciendo y listos para afrontar nuestro próximo capítulo, SCW 2.0, como líderes en gestión de riesgos para desarrolladores.