Data on Demand in Spring Roo

Wenn man mit Spring Roo arbeitet, wird die Erstellung von Testfällen erleichtert. Hierzu muss man beim Erzeugen einer entity nur die Option --testAutomatically angeben. Roo erzeugt dann entsprechende Integrationstestfälle. Nur: wo kommen die Testdaten her?

Hierzu wird zu einer Entity XXX die ITD (s.u.) XXXDataOnDemand_Roo_DataOnDemand.aj erzeugt. Es stehen folgende Funktionen zur Verfügung:

/** Erzeugt eine Instanz der Entity, die NICHT persistent ist. */
XXX getNewTransientXXX(int index);

/** Erzeugt eine persistente Instanz der Entity. */
XXX getSpecificXXX(int index);

/** Liefert eine zufällige, persistente Instanz zurück. */
XXX getRandomXXX();

/** Legt fest, ob das Objekt verändert werden kann. */
boolean modifyXXX(XXX object);

/** Initialisiert die persistenten Instanzen der Entity. */
void init();

/** Diese Methoden können überschrieben werden und sollten Werte liefern, die erlaubt sind. */
void setFIELDNAME(Object value);

Hier mal ein Beispiel, wie so eine Testklasse für die Entity „Country“ aussehen könnte:

@RooDataOnDemand( entity = Country.class )
public class CountryDataOnDemand {
	private Country[] data;

	{
		final List countries = new ArrayList( );
		countries.add( new Country( "Deutschland", "DE", "49" ) );
		countries.add( new Country( "Österreich", "AT", "43" ) );
		countries.add( new Country( "Schweiz", "CH", "41" ) );
		countries.add( new Country( "Niederlande", "NL", "31" ) );
		countries.add( new Country( "Belgien", "BE", "32" ) );
		countries.add( new Country( "Dänemark", "DK", "45" ) );
		countries.add( new Country( "Polen", "PL", "48" ) );
		countries.add( new Country( "Frankreich", "FR", "33" ) );
		countries.add( new Country( "Großbritannien", "UK", "44" ) );
		countries.add( new Country( "Schweden", "SE", "46" ) );

		data = countries.toArray( new Country[0] );
	}

	Country getNewTransientCountry( final int index ) {
		if (index < MAX_DATA_COUNT) {
			return new Country( data[index] );
		} else {
			return new Country( data[MAX_DATA_COUNT] );
		}
	}
}

Die Funktion init, die im ITD definiert wird, nimmt die ersten 10 Einträge, die getNewTransientCountry liefert und persistiert diese. Alle weiteren Funktionen wie getRandomCountry oder getSpecificCountry greifen dann auf diese persistierten Einträge zurück.

Wie ihr bestimmt gemerkt habt, gibt es 2 Besonderheiten zu beachten:

  • Liefert in getNewTransientXXX nicht immer das gleiche Objekt zurück, sondern immer ein frisches. Sonst beschwert sich der Integrationstest, dass er ein bereits "detached"-Objekt erhält, d. h. er merkt sich, dass in einem anderen Test das Objekt bereits persistiert wurde. In meinem Beispiel habe ich das Problem mit einem Copy-Constructor gelöst, aber auch der Einsatz von clone ist hier möglich.
  • Einige Tests benötigen ein Objekt am Index MAX_INT bzw. allgemeiner ein besonderes, nicht persistiertes Objekt. Wird also ein Index über die von euch zur Verfügung gestellten Daten hinaus benötigt, liefert ein weiteres Objekt zurück, das nicht mit einem bisher gelieferten Objekt identisch ist.

Links:
Schnelle Einführung in ITDs: http://spring-roo.blogspot.de/2011/10/quick-introduction-to-aspectj-itd.html

Literatur:
Eine gute Erläuterung des Themas findet man in Spring Roo in Action

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.