Oct
21
2009

(ITA) - TESTING & Magnolia

Prima di chiedersi come si fa a testare, occorre chiedersi “cosa” testare e perchè.
Se il perchè può essere ovvio, il “cosa” no e spesso è la chiave di volta per dei test di successo.

Cosa NON testare:

- funzionalità “core” di Magnolia: per queste ci affidiamo ad un prodotto, si spera che sia testato
- funzionalità “core” di Java / Tomcat / Loadbalancer / Sistemi di rete, ecc… non è compito dei test applicativi testare queste cose

Cosa vale la pena di testare

- funzionalità di business logic
- grafica
- interazioni via browser
- integrazioni con sistemi legacy / esterni
- scritture / letture / interazioni con dati da fonti esterne
- tutto quello che viene costruito “sopra” il mattoncino Magnolia

In un progetto Java, ci sono principalmente due modi per effettuare test:

1) Test in fase di build
2) Continuos Integration [3]

Mentre la seconda modalità prevede l’utilizzo di un ambiente di test separato, integrazione con SVN, definizione rigorosa di suite di test, ecc… (ovvero, è al momento troppo costoso!) si può procedere con la prima modalità.

In fase di build si possono quindi fare test di due tipi:
1) Test funzionali, puramente java-based
2) Test di “container”, ovvero simulando il deploy dell’artifact in un container (tomcat)

La suite di test da utilizzare è TestNG [1]. In alternativa è possibile ad esempio utilizzare JUnit, che si integra anch’essa con Surefire.
I test sono da effettuare in fase di build (Maven build).
Per utilizzare testNG è sufficiente dichiarare questa dipendenza all’interno del parent POM:

<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>5.8</version>
    <scope>test</scope>
    <classifier>jdk15</classifier>
</dependency>

ed utilizzare il plugin

<build>
	<plugins>
		...
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-surefire-plugin</artifactId>
			<version>2.4.3</version>
		</plugin>
		...
	</plugins>
<build>

I test saranno eseguiti dal plugin Surefire come test TestNG.
Per ulteriori informazioni su Surefire e TestNG vedi [2]

A questo punto occorre chiedersi cosa è possibile testare con un’ambiente di questo tipo a disposizione.
Sicuramente è possibile testare i metodi di utility, le integrazioni con sistemi esterni (lettura di feed RSS, accesso a DB, ecc..).
L’unica cosa a cui bisogna porre attenzione è lo “scope” del test.
Un test eseguito in fase di build di un modulo altro non può testare che le funzionalità esclusive del modulo stesso o le integrazioni del modulo con l’ambiente di deploy.
Non è possibile testare le interazioni del modulo con altri moduli.

Es1: vorrei testare la spedizione di una newsletter

artifact: example-magnolia-newsletter.jar
metodo da testare: NewsletterUtil.sendNewsletter(recipientList, newsletterIstance, delay);
presupposti: occorre avere a disposizione l’architettura dei server / servizi da utilizzare per spedire la newsletter

OK, è testabile.

Es2: vorrei testare la spedizione di una newsletter LEGGENDO gli indirizzi dal DMS Alfresco, utilizzando il modulo example-magnolia-dms.jar

artifact: example-magnolia-newsletter.jar
metodo da testare: NewsletterUtil.sendNewsletter(DMSUtil.getRecipient(id), newsletterIstance, delay);
presupposti: occorre avere a disposizione l’architettura dei server / servizi da utilizzare per spedire la newsletter

NON è testabile, a meno di non avere un ambiente di test “reale” –> Continuos Integration

Vi è un altro tipo di test, particolare dell’ambiente di sviluppo di Magnolia.
E’ possibile effettuare dei test automatici che simulano l’interazione della nostra applicazione con un browser.
Per fare questo occorre utilizzare Selenium [4].
Selenium si compone di due parti, la parte server (o grid) ha il compito di eseguire in un browser i comandi che la parte client invia tramite connessione TCP su porta 4444 (default).

Gli step da percorrere sono i seguenti:
1) Configurare l’utilizzo di Surefire e TestNG
2) Far partire Selenium Remote Command in fase di pre-integration-test [5]. (* perchè in questa fase?)
3) Far partire un container nel quale “deployare” l’applicazione web
4) DEPLOY -> Magnolia + Modulo
5) Eseguire i test Selenium
6) Spegnere il container e il server Selenium

-> 1) Vedi sopra (Surefire + TestNG)
-> 2) Occorre utilizzare un plugin (selenium-maven-plugin), in fase di pre-integration-test

<build>
	<plugins>
		...
		<plugin>
			<groupId>org.codehaus.mojo</groupId>
			<artifactId>selenium-maven-plugin</artifactId>
			<executions>
				<!-- start Selenium server before test execution -->
        		<execution>
           			<id>start</id>
           			<phase>pre-integration-test</phase>
           			<goals>
               			<goal>start-server</goal>
           			</goals>
           			<configuration>
               			<background>true</background>
               			<logOutput>true</logOutput>
						<multiWindow>true</multiWindow>
           			</configuration>
        		</execution>
        		<!-- stop Selenium server after test execution -->
        		<execution>
           			<id>stop</id>
           			<phase>post-integration-test</phase>
           			<goals>
               			<goal>stop-server</goal>
           			</goals>
        		</execution>
    		</executions>
		</plugin>
		...
	</plugins>
</build>

-> 3) Per far partire Tomcat (il container di riferimento per la piattaforma) occorre utilizzare l’ennesimo plugin (cargo-maven-plugin), in fase di pre-integration-test

<build>
	<plugins>
		...
		<plugin>
			<inherited>true</inherited>
			<groupId>org.codehaus.cargo</groupId>
			<artifactId>cargo-maven2-plugin</artifactId>
			<configuration>
 
				<!-- Container configuration -->
				<container>
				<containerId>tomcat6x</containerId>
					<!-- container.home: indica dove andare a prendere i file originari di tomcat -->
					<home>c:/dev/apache-tomcat/apache-tomcat-6.0.20</home>
					<output>${project.build.directory}/cargo/tomcat.log</output>
					<log>${project.build.directory}/cargo/cargo.log</log>
				</container>
 
				<!-- Configuration to use with the above container -->
				<configuration>
					<!-- configuration.home: indica dove far girare il container -->
					<home>${project.build.directory}/tomcat/container</home>
					<properties>
						<cargo.servlet.port>8090</cargo.servlet.port><!-- utilizzare 8090, in quanto è possibile avere altre istanze attive -->
						<cargo.logging>high</cargo.logging>
						<cargo.jvmargs>${heap.pre} ${heap.max} ${permsize}</cargo.jvmargs>
					</properties>
				</configuration>
 
				<!--  
					By default the Maven2 plugin will wait after the container is started. 
					It means that you have to either press Ctrl-C or to run cargo:stop from another shell to stop it. 
					If you are using Cargo to automate your functional tests, you'll want the plugin 
					not to wait so that you can execute your tests after the container is started. 
					To achieve this simply specify <wait>false</wait> in the Cargo's configuration in your pom.xml.
				-->
				<wait>false</wait>
			</configuration>
 
			<executions>
				<!-- start container before tests execution -->
				<execution>
					<id>start-container</id>
					<phase>pre-integration-test</phase>
					<goals>
						<goal>start</goal>
						<goal>deploy</goal>
					</goals>
				</execution>
 
				<!-- stop container before tests execution -->
				<execution>
					<id>stop-container</id>
					<phase>post-integration-test</phase>
					<goals>
						<goal>stop</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
		...
	</plugins>
</build>

-> 4) Questa è la fase più delicata. Una volta partito tomcat occorre deployare all’interno webapp Magnolia, possibilimente già installata e con licenza EE, e occorre deployare al suo interno il modulo in questione.
Per fare questo ci sono due opzioni:
A) Procedere con un deploy configurato in cargo:

modificare:

		<!-- start container before tests execution -->
		<execution>
			<id>start-container</id>
			<phase>pre-integration-test</phase>
			<goals>
				<goal>start</goal>
				<goal>deploy</goal>
			</goals>
		</execution>

in:

		<!-- start container before tests execution -->
		<execution>
			<id>start-container</id>
			<phase>pre-integration-test</phase>
			<goals>
				<goal>start</goal>
				<goal>deploy</goal>
			</goals>
			<configuration>
				<deployer>
					<deployables>
						<deployable>
							<group-id>com.example.magnolia</group-id>
							<artifactId>magnoliaAuthor</artifactId>
							<type>war</type>
							<pingURL>http://localhost:8090/magnoliaAuthor/.magnolia/pages/adminCentral.html?mgnlUserId=superuser&amp;mgnlUserPSWD=superuser</pingURL>
							<pingTimeout>180000</pingTimeout>
							<properties>
								<context>magnoliaAuthor</context>
							</properties>
						</deployable>	
					</deployables>
				</deployer>
			</configuration>
		</execution>

in questo modo, il WAR identificato dal gruppo Maven indicato verrà deployato all’interno del container.
Rimane ancora il problema di integrare il progetto attualmente in fase di build con il file WAR e di eseguire l’installazione di Magnolia.

B) Procedere con un deploy “manuale”, mediato da task ant

è possibile definire un task ant da eseguire in una qualunque fase di esecuzione di una maven build.

<build>
			<plugins>
				...
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-antrun-plugin</artifactId>
					<executions>
						<execution>
							<id>copyModule</id>
							<phase>pre-integration-test</phase>
							<configuration>
								<tasks>
									<echo>Copy module ${project.build.finalName}.jar</echo>
									<copy 
										file="target/${project.build.finalName}.jar"
										todir="../magnoliaAuthor-integrationTest/src/main/magnoliaAuthor/WEB-INF/lib"
										overwrite="true" />
								</tasks>
							</configuration>
							<goals>
								<goal>run</goal>
							</goals>
						</execution>
 
						<!-- cancella il file dopo i test -->					
						<execution>
							<id>deleteModule</id>
							<phase>post-integration-test</phase>
							<configuration>
								<tasks>
									<echo>Delete module  ${project.name}</echo>
									<delete>
										<fileset 
											dir="../magnoliaAuthor-integrationTest/src/main/magnoliaAuthor/WEB-INF/lib"
										    includes="${project.build.finalName}*.jar" />
									</delete>
								</tasks>
							</configuration>
							<goals>
								<goal>run</goal>
							</goals>
						</execution>
					</executions>
				</plugin>
				...
			</plugins>
		</build>

A questo punto occorre modificare Cargo, in modo da caricare la webapp di integration:

		<configuration>
			<deployer>
				<deployables>
					<deployable>
						<type>war</type>
						<location>../magnoliaAuthor-integrationTest/src/main/magnoliaAuthor</location>
						<pingURL>http://localhost:8080/magnoliaAuthor/demo-project.html?mgnlUserId=superuser&amp;mgnlUserPSWD=superuser</pingURL>
						<pingTimeout>180000</pingTimeout>
					</deployable>
				</deployables>
			</deployer>
		</configuration>

La webapp sarà quindi deployata non più come war, ma come semplice “copia e incolla” di cartella e conterrà al suo interno il file da testare.

-> 5) I test partono e se contengono invocazioni remote a Selenium queste saranno eseguite e si vedrà “apparire” sullo schermo un browser che eseguirà i comandi richiesti.
-> 6) Le dichiarazioni dei plugin precedenti contengono due fasi di esecuzione: quella relativa alla fase “post-integration-test” avviene dopo aver eseguito i test.

PUNTI APERTI:

è possibile partire dalla empty webapp di magnolia e utilizzare un cargo che carica:
- empty webapp CE (versione X)
- moduli EE dichiarati per la versione (X)
- modulo aggiuntivo da testare
- effettua l’installazione del repository
- effettua il caricamento della licenza
?

E’ possibile / ha senso avere un WAR di test collegato ad un repository di test, in modo da evitare la fase di installazione?

NB: per testare funzionalità core di Magnolia e precisamente legate a:
- Content
- Context
- HierarchyManager
è possibile utilizzare delle classi di mockup (http://www.easymock.org) che facilitano l’interazione con questi oggetti.
Vedere [7]

————————————————
[1] http://testng.org
[2] http://maven.apache.org/plugins/maven-surefire-plugin/testng.html
[3] http://en.wikipedia.org/wiki/Continuous_integration
[4] http://seleniumhq.org
[5] http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Lifecycle_Reference
[6] http://mojo.codehaus.org/selenium-maven-plugin/
[7] http://wiki.magnolia-cms.com/display/DEV/Testing+Magnolia

Leave a Reply