2010-09-20 17 views
17

Estoy tratando de acelerar las pruebas de integración en nuestro entorno. Todas nuestras clases están auto conectadas. En nuestro archivo applicationContext.xml hemos definido los siguientes:La prueba de integración de muelles es lenta con autoenvío

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

me he dado cuenta de que la primavera está escaneando todos los directorios indicados anteriormente y luego itera sobre cada grano y almacena en caché las propiedades de cada uno. (Fui a través de los mensajes de depuración de la primavera)

Como resultado, la siguiente prueba tarda unos 14 segundos para correr:

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

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

Idealmente, solo se crean instancias de los beans requeridos para la prueba.

gracias de antemano.

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

Respuesta

1

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

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

+0

Así que la idea es tener un contexto de aplicación separada (s) para la prueba (s) ... cada vez que tengo una clase test1 donde tengo que usar otro bean, lo agrego al contexto test1 y no uso escaneo de componentes. O utilice el escaneo de componentes e intente crear pruebas de acuerdo con los paquetes, lo que parece ser una tontería. – lisak

+0

Pensé en esto, pero estaba tratando de evitar la definición de un archivo de contexto personalizado por archivo de prueba. Estamos utilizando estas pruebas para las pruebas de integración parcial (necesitan llegar a la base de datos). – Tihom

1

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

Adición: Si eso no es suficiente y se están utilizando JUnit, puede que quiera usar una utilidad del proyecto JUnit Addons. La clase DirectorySuiteBuilder construye dinámicamente un banco de pruebas a partir de una estructura de directorios. Entonces puede hacer algo como

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

Al inicializar 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 de primavera "limpio", entonces probablemente esté perdido.

+0

El proyecto es lo suficientemente grande como para que esto no sea realmente factible. Hemos autoconectado casi todo. – Tihom

2

Un enfoque es omitir completamente la autodetección y cargar un contexto separado (con los componentes necesarios para la prueba) o redefinir los beans en tiempo de ejecución (antes de ejecutar la prueba).

Este hilo discute redefinición de los granos y una clase de prueba personalizada para hacer esto:

Spring beans redefinition in unit test environment

+0

+1 para señalar cosas que no sabía acerca de las pruebas de primavera – Ither

0

En este tipo de situación, tendrá que encontrar un equilibrio. Por un lado, con razón desea 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 debería mantener la configuración de las pruebas lo más simple posible, por lo que el mantenimiento del conjunto de pruebas no sería demasiado engorroso para ser útil.

Pero al final del día, tendrá que encontrar su propio equilibrio y tomar una decisión. Recomendaría crear algunos archivos de configuración de contexto para probar para agrupar algunas pruebas, por lo que una prueba simple no tomaría mucho tiempo simplemente configurándola Spring, mientras mantiene la cantidad de archivos de configuración al mínimo que puede administrar.

14

Si realmente desea acelerar su contexto de aplicación, deshabilitar su < componente de exploración y realiza 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, permitir < contexto: Anotación- config/>

Como necesita realizar la rutina anterior antes de ejecutar cualquier prueba, puede crear una clase bstract donde se puede ejecutar el siguiente

Establecer una propiedad del sistema Java de entorno de pruebas 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, simplemente se extiende inicializador

+0

@mkoryak Y habilitar ** default-lazy-init = "true" ** –

+0

Encontramos que el escaneo tardó aproximadamente 4 segundos y se creó el árbol de dependencias unos 10 segundos. ¿Esto reducirá el tiempo de escaneo o el tiempo del árbol de dependencias o ambos? – Tihom

+0

@Tihom Solo necesita ejecutar una vez. Nada más. Creará su contraparte xml y evitará la sobrecarga de reflexión –

0

Dado que ninguna de las respuestas aquí me solucionó este problema, agrego mi propia experiencia.

Mi problema fue que Spring, Hibernate y EhCache se agruparon en un intento de ahogamiento de mi consola con mensajes detallados DEBUG, lo que produjo un registro ilegible y, lo que es peor, un bajo rendimiento insoportable.

Configuración de sus niveles de registro fijos todo:

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