Kürzlich wollte ich einen Aspekt zu einem Domain-Objekt hinzufügen, so dass es gespeichert wurde, sobald es seinen Zustand änderte. Nachdem ich diesen Aspekt hinzugefügt hatte, schlug der gesamte Build natürlich fehl, da viele der Unit-Tests die Aufrufe, die nun in das Domain-Objekt eingewoben waren, nicht erwarteten.
Natürlich könnte ich alle Unit-Tests so ändern, dass sie die Änderung im Code widerspiegeln. Aber das scheint dem ganzen Zweck des Aspekts zu widersprechen. Eine andere Möglichkeit ist natürlich, das Weben bis nach den Unit-Tests zu verschieben. Auch das schien mir nicht die richtige Lösung zu sein, denn ich wollte zumindest einige Tests schreiben, um zu prüfen, ob der Aspekt seine Aufgabe erfüllt. Wie konnte ich das also umgehen? Die Antwort lag in Spring AOP. Es teilt einen Großteil der Syntax von AspectJ, obwohl es (noch) nicht alle Funktionen bietet. Zu Ihrem Vergnügen habe ich ein kleines Beispiel erstellt. Zunächst sehen wir uns eine einfache Domäne ohne Aspekte an. Opfer.java
public class Victim {
private int itemsInPosession;
public Victim(int itemsInPosession) {
this.itemsInPosession = itemsInPosession;
}
public void itemStolen() {
wenn (itemsInPosession > 0) {
itemsInPosession--;
}
}
public int getItemsInPosession() {
return itemsInPosession;
}
}
Und Dieb.java
public class Dieb {
public void stehlen(Opfer Opfer) {
victim.itemStolen();
}
}
Natürlich haben wir einen Einheitstest, um zu prüfen, ob der Dieb tatsächlich ein Opfer bestiehlt:
public class ThievingTest extends TestCase {
public void testShouldSucceedInStealing() {
Opfer Opfer = new Opfer(1000);
Dieb Dieb = new Dieb();
Dieb.stehlen(Opfer);
assertEquals(999, victim.getItemsInPosession());
}
}
Die Durchführung dieses Tests zeigt, dass es dem Dieb gelingt, dem Opfer einen Gegenstand zu stehlen. Aber natürlich können wir nicht zulassen, dass die Diebe die Opfer wahllos bestehlen. Wir müssen einen Polizeiagenten einführen, der den Dieb ins Gefängnis bringen kann. Fügen wir eine Schnittstelle zu Jail hinzu und schreiben wir einen neuen Test, der besagt, dass der Dieb wegen Diebstahls ins Gefängnis kommt. Gefängnis.java
public interface Jail {
public void putInJail(Dieb Dieb);
}
Und die zweite Unit-Test-Klasse:
public class ThievingJailTest extends TestCase {
Privatgefängnis;
public void setUp() {
jail = EasyMock.createMock(Jail.class);
}
public void testShouldLandInJailForStealing() {
Opfer Opfer = new Opfer(1000);
Dieb Dieb = new Dieb();
jail.putInJail(Dieb);
EasyMock.replay(jail);
Dieb.stehlen(Opfer);
EasyMock.verify(jail);
assertEquals(1000, victim.getItemsInPossession());
}
}
Natürlich schlägt dieser Test fehl, denn es gibt noch keine Möglichkeit, den Dieb ins Gefängnis zu bringen. Fügen wir den PoliceAgent als Aspekt hinzu, denn wir wollen den Dieb, der stiehlt, abfangen: PolizeiAgentAspect.java
@Aspekt
public class PoliceAgentAspect {
Privatgefängnis;
@Around("execution(void *Thief.steal(..))")
public void arrestThief(ProceedingJoinPoint joinPoint) {
Thief thief = (Thief) joinPoint.getThis();
jail.putInJail(Dieb);
}
public void setJail(Jail jail) {
this.jail = jail;
}
}
Damit Spring AOP den Aspekt erkennt und die Verkabelung vornimmt, müssen wir eine applicationContext.xml mit den richtigen Beans hinzufügen. In diesem einfachen Beispiel reicht die folgende Datei aus (ich habe die Namespace-Deklarationen zur besseren Lesbarkeit entfernt):
Sie können sehen, dass ich im Spring-Kontext die Jail gespottet habe. Dieser Code befand sich zuvor im Einheitstest. Außerdem habe ich den Dieb als Bean hinzugefügt, die injiziert werden kann. Dadurch wird sichergestellt, dass Spring den Dieb mit dem PoliceAgentAspect abfangen kann. Der geänderte Test sieht wie folgt aus:
public class ThievingJailTest extends AbstractDependencyInjectionSpringContextTests {
Privatgefängnis;
privater Dieb Dieb;
@Override
protected String[] getConfigLocations() {
setAutowireMode(AUTOWIRE_BY_NAME);
return new String[] {"applicationContext.xml"};
}
public void testShouldBePutInJailByPoliceAgentAspect() {
Victim v = new Victim(1000);
jail.putInJail(Dieb);
EasyMock.replay(jail);
dieb.stehlen(v);
EasyMock.verify(jail);
assertEquals(1000, v.getItemsInPosession());
}
public void setJail(Jail jail) { this.jail = jail; }
public void setThief(Dieb Dieb) { this.Dieb = Dieb; }
Wenn wir diesen Test jetzt ausführen, ist er erfolgreich. Auch unser alter Test läuft immer noch einwandfrei und liefert ein grünes Licht. Mit Spring AOP können wir sicherstellen, dass unser Code funktioniert, wenn wir keine Aspekte verwenden, und dass das Hinzufügen von Aspekten zu unserem Code die beabsichtigten Ergebnisse liefert.
Verfasst von

Jeroen van Erp
Unsere Ideen
Weitere Blogs
Contact



