TESTING & Magnolia


Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /membri/maips21/wp-content/plugins/wp-syntax/wp-syntax.php on line 380

Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /membri/maips21/wp-content/plugins/wp-syntax/wp-syntax.php on line 380

Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /membri/maips21/wp-content/plugins/wp-syntax/wp-syntax.php on line 380

Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /membri/maips21/wp-content/plugins/wp-syntax/wp-syntax.php on line 380

Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /membri/maips21/wp-content/plugins/wp-syntax/wp-syntax.php on line 380

Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /membri/maips21/wp-content/plugins/wp-syntax/wp-syntax.php on line 380

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>
<versionid>5.14</versionid>
</dependency>
...

ed utilizzare il plugin

...
<plugin>
<groupid>org.apache.maven.plugins</groupid>
<artifactid>maven-surefire-plugin</artifactid>
<versionid>2.4.3</versionid>
</plugin>
...

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

...
<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>
...

-> 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

...
<plugin>
	<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/tomcat6x.log</output>
			<log>${project.build.directory}/cargo/cargo.log</log>
		</container>
 
		<!-- Configuration to use with the container -->
		</configuration><configuration>
			<!-- configuration.home: indica dove far girare il container -->
			<home>${project.build.directory}/tomcat6x/container</home>
			<properties>
				<cargo .servlet.port>8090</cargo>
				<cargo .logging>high</cargo>
				<cargo .jvmargs>${heap.pre} ${heap.max} ${permsize}</cargo>
			</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 in the Cargo's configuration in your pom.xml.
		-->
		<wait>false</wait>
 
 
	<executions>
		<!-- start container before tests execution -->
		<execution>
			<id>start-container</id>
			<phase>${core.plugins.cargo.phase01}</phase>
			<goals>
				<goal>start</goal>
				<goal>deploy</goal>
			</goals>
 
			<configuration>
				<deployer>
					<deployables>
 
							<!--  
						<deployable>
							<type>war</type>
							<location>${webapp.home}</location>
							<pingurl>http://localhost:8080/magnoliaAuthor?mgnlUserId=superuser&amp;mgnlUserPSWD=superuser</pingurl>
							<pingtimeout>180000</pingtimeout>
							<properties>
								<context>magnoliaAuthor</context>
							</properties>
 
					</deployables>
					-->
						<deployable>
							<type>war</type>
							<location>${webapp.home}.war</location>
							<pingurl>http://localhost:8090/magnoliaAuthor/demo-project.html?mgnlUserId=superuser&amp;mgnlUserPSWD=superuser</pingurl>
							<pingtimeout>180000</pingtimeout>
							<properties>
								<context>magnoliaAuthor</context>
							</properties>
						</deployable>
 
				</deployer>
			</configuration>
		</execution>
 
		<!-- stop container before tests execution -->
		<execution>
			<id>stop-container</id>
			<phase>${core.plugins.cargo.phase02}</phase>
			<goals>
				<goal>stop</goal>
			</goals>
		</execution>
	</executions>
</plugin>
...

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.

...
<plugin>
	<groupid>org.apache.maven.plugins</groupid>
	<artifactid>maven-antrun-plugin</artifactid>
	<executions>
		<execution>
			<id>copyModule</id>
			<phase>${core.plugins.antrun.phase01}</phase>
			<configuration>
				<tasks>
					<property name="emptymagnolia.home" value="${workspace.home}/magnolia-authorInstance-empty-4.1/src/main/webapp"></property>
 
					<echo>Creating an empty temp dir: ${webapp.home}</echo>
 
					<mkdir dir="${webapp.home}"></mkdir>
					<delete>
						<fileset dir="${webapp.home}" includes="**/*"></fileset>
					</delete>
					<mkdir dir="${webapp.home}"></mkdir>
 
					<echo>Preparing empty webapp (Magnolia Author 4.1 - with installed repo - with licence)</echo>
 
					<copy todir="${webapp.home}">
						<fileset dir="${emptymagnolia.home}"></fileset>
					</copy>
 
					<echo>Preparing module JAR inside webapp</echo>
					<copy file="target/${project.build.finalName}.jar" todir="${webapp.home}/WEB-INF/lib" overwrite="true"></copy>
 
					<echo>Waring...</echo>
					<delete file="${webapp.home}.war"></delete>
 
					<zip destfile="${webapp.home}.war" basedir="${webapp.home}" update="true"></zip>
 
					<echo>It's cargo time!</echo>
 
				</tasks>
			</configuration>
			<goals>
				<goal>run</goal>
			</goals>
		</execution>
 
		<!-- cancella il file dopo i test -->					
		<execution>
			<id>deleteModule</id>
			<phase>${core.plugins.antrun.phase02}</phase>
			<configuration>
				<tasks>
					<echo>Cleaning temp dirs</echo>
					<delete>
						<fileset dir="${webapp.home}" includes="*.java"></fileset>
					</delete>
				</tasks>
			</configuration>
			<goals>
				<goal>run</goal>
			</goals>
		</execution>
	</executions>
</plugin>
...

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

...
<deployable>
	<type>war</type>
	<location>${webapp.home}.war</location>
	<pingurl>http://localhost:8090/magnoliaAuthor/demo-project.html?mgnlUserId=superuser&amp;mgnlUserPSWD=superuser</pingurl>
	<pingtimeout>180000</pingtimeout>
	<properties>
		<context>magnoliaAuthor</context>
	</properties>
</deployable>
...

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

Latest articles

Matteo Pelucco Written by:

4 Comments

  1. admin
    October 28

    Yes, indeed.
    It is our internal (Tinext) first approach on testing a Magnolia based module / site.
    We scouted a possible solution and we realized something, but it is definitely “embrional”.
    If I manage to reserve a hour, I try to set up a simple test based upon mock jcr repository and Selenium..

    You say maintainance: Maintainance vs. Project budget.. the evergreen “Mission Impossible”?

  2. October 29

    well, that, and how the tests survive passage of time – how brittle they can be, if they rely on the html structure, for example. (Well, all this should become better with Magnolia 5, but testing the M4 or M3 admin interface would be … not so fun…)

  3. admin
    October 29

    “not so fun” sounds like an euphemism!
    Our intent was to test a bunch of functionalities we added to STK, but for now nothing seems to be easy to maintain.. because we change our code a lot, almost every week, and so.. you know 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *


seven − = 3