unitarias pruebas integracion framework java unit-testing spring autowired

java - integracion - pruebas unitarias mockito



Prueba de integraciĆ³n de primavera es lenta con autowiring (7)

Como ninguna de las respuestas aquí me resolvió este problema, agrego mi propia experiencia.

Mi problema fue que Spring, Hibernate y EhCache se agruparon en el intento de ahogar mi consola con mensajes DEBUG detallados, lo que resultó en un registro ilegible y, mucho peor, un bajo rendimiento insoportable.

Configurando sus niveles de registro arreglados todo arriba:

Logger.getLogger("org.hibernate").setLevel(Level.INFO); Logger.getLogger("net.sf.ehcache").setLevel(Level.INFO); Logger.getLogger("org.springframework").setLevel(Level.INFO);

Estoy tratando de acelerar las pruebas de integración en nuestro entorno. Todas nuestras clases son automáticas. En nuestro archivo applicationContext.xml hemos definido lo siguiente:

<context:annotation-config/> <context:component-scan base-package="com.mycompany.framework"/> <context:component-scan base-package="com.mycompany.service"/> ...additional directories

He notado que Spring está escaneando todos los directorios indicados anteriormente y luego itera sobre cada bean y almacena en caché las propiedades de cada uno. (Repasé los mensajes de DEBUG de la primavera)

Como resultado, la siguiente prueba tarda unos 14 segundos en ejecutarse:

public class MyTest extends BaseSpringTest { @Test def void myTest(){ println "test" } }

¿Hay alguna manera de cargar la configuración perezosamente? Intenté agregar default-lazy-init="true" pero eso no funcionó.

Idealmente, solo se instancian los frijoles requeridos para la prueba.

gracias por adelantado.

Actualización : Debería haber dicho esto antes, no quiero tener un archivo de contexto para cada prueba. Tampoco creo que un solo archivo de contexto funcione solo para las pruebas. (Este archivo de contexto de prueba terminaría incluyendo todo)


En este tipo de situación, tendrá que encontrar un equilibrio. Por un lado, desearía realizar las pruebas en el menor tiempo posible para obtener resultados rápidos. Esto es especialmente importante cuando se trabaja en un entorno de equipo con trabajo de integración continua. Por otro lado, también querrá, con razón, mantener la configuración de las pruebas lo más simple posible para que el mantenimiento del conjunto de pruebas no resulte tan engorroso como para ser útil.

Pero al final del día, tendrá que encontrar su propio saldo y tomar una decisión. Recomendaría crear unos pocos archivos de configuración de contexto para las pruebas para agrupar algunas pruebas, por lo que una prueba tan simple no tomaría mucho tiempo, simplemente la configuraría Spring, mientras mantiene el número de archivos de configuración al mínimo que puede administrar.


Este es el precio que paga por la detección automática de componentes: es más lento. Aunque su prueba solo requiere ciertos beans, su <context:component-scan> es mucho más amplio, y Spring creará una instancia e inicializará cada bean que encuentre.

Le sugiero que utilice un archivo de beans diferente para sus pruebas, uno que solo defina los beans necesarios para la prueba en sí, es decir, que no use <context:component-scan> .


Probablemente lo que necesita es refactorizar su configuración para usar menos cableado automático. Mi enfoque es casi siempre conectar los beans por su nombre, tratando de ser explícito con el diseño pero, al mismo tiempo, tampoco es demasiado detallado, utilizando autowiring cuando está claro que lo está usando para ocultar detalles menores.

Addendum: si eso no es suficiente y está utilizando junit, es posible que desee usar una utilidad del proyecto de complementos JUnit . La clase DirectorySuiteBuilder construye dinámicamente un conjunto de pruebas a partir de una estructura de directorios. Para que puedas hacer algo como

DirectorySuiteBuilder builder = new DirectorySuiteBuilder(); Test suite = builder.suite("project/tests");

Inicializando el contexto de Spring antes de este código, puede ejecutar todas las pruebas a la vez. Sin embargo, si cada prueba asume un contexto Spring "limpio", es probable que esté perdido.


Un método es omitir la detección automática por completo y cargar un contexto separado (con los componentes necesarios para la prueba) o redefinir sus beans en tiempo de ejecución (antes de que se ejecute la prueba).

Este hilo trata sobre la redefinición de beans y una clase de prueba personalizada para hacer esto:

Redefinición de frijoles de primavera en ambiente de prueba unitaria



Si realmente desea acelerar el contexto de su aplicación , deshabilite su <componente-scan y realice la siguiente rutina antes de ejecutar cualquier prueba

Resource resource = new ClassPathResource(<PUT_XML_PATH_RIGHT_HERE>); // source.xml, for instance InputStream in = resource.getInputStream(); Document document = new SAXReader().read(in); Element root = document.getRootElement(); /** * remove component-scanning */ for ( Iterator i = root.elementIterator(); i.hasNext(); ) { Element element = (Element) i.next(); if(element.getNamespacePrefix().equals("context") && element.getName().equals("component-scan")) root.remove(element); } in.close(); ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(true); for (String source: new String[] {"com.mycompany.framework", "com.mycompany.service"}) { for (BeanDefinition bd: scanner.findCandidateComponents(source)) { root .addElement("bean") .addAttribute("class", bd.getBeanClassName()); } } //add attribute default-lazy-init = true root.addAttribute("default-lazy-init","true"); /** * creates a new xml file which will be used for testing */ XMLWriter output = new XMLWriter(new FileWriter(<SET_UP_DESTINATION_RIGHT_HERE>)); output.write(document); output.close();

Además de eso, habilite <context: annotation-config />

Como necesita realizar la rutina anterior antes de ejecutar cualquier prueba, puede crear una clase abstracta donde pueda ejecutar lo siguiente

Configure una propiedad del sistema Java para el entorno de prueba de la siguiente manera

-Doptimized-application-context=false

Y

public abstract class Initializer { @BeforeClass public static void setUpOptimizedApplicationContextFile() { if(System.getProperty("optimized-application-context").equals("false")) { // do as shown above // and System.setProperty("optimized-application-context", "true"); } } }

Ahora, para cada clase de prueba, solo se extiende Initializer