Estoy tratando de escribir una Prueba de Unidad para un bean simple que se usa en mi programa para validar formularios. El bean se anota con @Component
y tiene una variable de clase que se inicializa usando
@Value("${this.property.value}") private String thisProperty;
Me gustaría escribir pruebas unitarias para los métodos de validación dentro de esta clase, sin embargo, si es posible, me gustaría hacerlo sin utilizar el archivo de propiedades. Mi razonamiento detrás de esto es que si el valor que obtengo del archivo de propiedades cambia, me gustaría que eso no afecte mi caso de prueba. Mi caso de prueba es probar el código que valida el valor, no el valor en sí.
¿Hay alguna manera de usar el código Java dentro de mi clase de prueba para inicializar una clase Java y llenar la propiedad Spring @Value dentro de esa clase y luego usar eso para probar?
Encontré este How To que parece estar cerca, pero todavía usa un archivo de propiedades. Prefiero que todo sea código Java.
Respuestas:
Si es posible, trataría de escribir esas pruebas sin Spring Context. Si crea esta clase en su prueba sin resorte, entonces tiene control total sobre sus campos.
Para configurar el
@value
campo, puede usar SpringsReflectionTestUtils
: tiene un métodosetField
para configurar campos privados.@ver JavaDoc : ReflectionTestUtils.setField (java.lang.Object, java.lang.String, java.lang.Object)
fuente
org.springframework.test.util.ReflectionTestUtils.setField(classUnderTest, "field", "value");
@Value
anotación al parámetro del constructor. Esto hace que el código de prueba sea mucho más simple al escribir el código manualmente, y Spring Boot no le importa.Desde Spring 4.1, puede configurar valores de propiedad solo en el código mediante el uso de
org.springframework.test.context.TestPropertySource
anotaciones en el nivel de clase de Pruebas unitarias. Puede usar este enfoque incluso para inyectar propiedades en instancias de beans dependientesPor ejemplo
Nota: Es necesario tener una instancia
org.springframework.context.support.PropertySourcesPlaceholderConfigurer
en contexto SpringEditar 24-08-2017: Si está utilizando SpringBoot 1.4.0 y posterior, puede inicializar las pruebas
@SpringBootTest
y las@SpringBootConfiguration
anotaciones. Más información aquí.En el caso de SpringBoot tenemos el siguiente código
fuente
No abuses de los campos privados que obtienes / establece por reflexión
Usar la reflexión como se hace en varias respuestas aquí es algo que podríamos evitar.
Aporta un pequeño valor aquí mientras presenta múltiples inconvenientes:
@Value String field
. Mañana puede declararlos5
o mencionarlos10
en esa clase y es posible que ni siquiera se dé cuenta de que disminuye el diseño de la clase. Con un enfoque más visible para establecer estos campos (como el constructor), lo pensará dos veces antes de agregar todos estos campos y probablemente los encapsulará en otra clase y los usará@ConfigurationProperties
.Haga que su clase sea comprobable tanto unitaria como en integración
Para poder escribir tanto pruebas unitarias simples (es decir, sin un contenedor de Spring en ejecución) como pruebas de integración para su clase de componente Spring, debe hacer que esta clase sea utilizable con o sin Spring.
Ejecutar un contenedor en una prueba unitaria cuando no es necesario es una mala práctica que ralentiza las compilaciones locales: no es necesario.
Agregué esta respuesta porque ninguna respuesta aquí parece mostrar esta distinción y, por lo tanto, dependen de un contenedor en ejecución sistemáticamente.
Así que creo que debería mover esta propiedad definida como interna de la clase:
en un parámetro constructor que será inyectado por Spring:
Ejemplo de prueba unitaria
Puede crear instancias
Foo
sin Spring e inyectar cualquier valorproperty
gracias al constructor:Ejemplo de prueba de integración
Puede inyectar la propiedad en el contexto con Spring Boot de esta manera simple gracias al
properties
atributo de@SpringBootTest
:Podría usar como alternativa,
@TestPropertySource
pero agrega una anotación adicional:Con Spring (sin Spring Boot), debería ser un poco más complicado, pero como no usé Spring sin Spring Boot desde hace mucho tiempo, no prefiero decir algo estúpido.
Como nota al margen: si tiene muchos
@Value
campos para establecer, extraerlos en una clase anotada@ConfigurationProperties
es más relevante porque no queremos un constructor con demasiados argumentos.fuente
final
, es decirprivate String final property
Si lo desea, aún puede ejecutar sus pruebas dentro de Spring Context y establecer las propiedades requeridas dentro de la clase de configuración Spring. Si usa JUnit, use SpringJUnit4ClassRunner y defina una clase de configuración dedicada para sus pruebas así:
La clase bajo prueba:
La clase de prueba:
Y la clase de configuración para esta prueba:
Dicho esto, no recomendaría este enfoque, solo lo agregué aquí como referencia. En mi opinión, una forma mucho mejor es usar el corredor Mockito. En ese caso, no ejecuta pruebas dentro de Spring, lo cual es mucho más claro y simple.
fuente
Esto parece funcionar, aunque todavía es un poco detallado (me gustaría algo más corto aún):
fuente
@TestProperty
anotación.@Value
s, independientemente de si la propiedad correspondiente está establecida o no.Agregar PropertyPlaceholderConfigurer en la configuración está funcionando para mí.
Y en clase de prueba
fuente