2013-05-03 7 views
7

Patrzę na AspectJ, aby sprawdzić, czy możemy go użyć w naszym pakiecie testowym.Czy AspectJ może zastąpić "nowy X" przez "nowy SubclassOfX" w kodzie biblioteki innej firmy?

Mamy dość dużą bibliotekę komunikacji Java innej firmy, która ma wbudowane własne klasy (które nie implementują żadnych interfejsów), co z kolei oznacza, że ​​potrzebujemy fizycznego zaplecza i poprawnie skonfigurowanego, aby móc przeprowadzać testy.

Przeglądam nasze opcje usuwania tego ograniczenia. Możliwe byłoby utworzenie podklasy kłopotliwych klas, a następnie poprosić AspectJ o zastąpienie "nowego X" przez "nowy OurSubclassOfX" podczas ładowania biblioteki strony trzeciej, ale jestem nowy w AspectJ iz mojego krótkiego przeglądania tej dokumentacji nie jest typowym przypadkiem użycia.

Czy AspectJ można to zrobić? Jaki byłby fragment kodu konfiguracji?

Odpowiedz

9

Tak, jest to możliwe. Załóżmy, że masz ciężko przewodowy klasę, ewentualnie ściągam coś z bazy danych, a chcesz wyśmiewać go poprzez aspekcie:

package de.scrum_master.aop.app; 

public class HardWired { 
    private int id; 
    private String name; 

    public HardWired(int id, String name) { 
     this.id = id; 
     this.name = name; 
    } 

    public void doSomething() { 
     System.out.println("Fetching values from database"); 
    } 

    public int getSomething() { 
     return 11; 
    } 

    @Override 
    public String toString() { 
     return "HardWired [id=" + id + ", name=" + name + "]"; 
    } 
} 

to istnieje niewiele aplikacji kierowca przy użyciu tej samej klasy (a nie interfejsu) :

package de.scrum_master.aop.app; 

public class Application { 
    public static void main(String[] args) { 
     HardWired hw = new HardWired(999, "My object"); 
     System.out.println(hw); 
     hw.doSomething(); 
     System.out.println(hw.getSomething()); 
    } 
} 

wyjście jest w następujący sposób:

HardWired [id=999, name=My object] 
Fetching values from database 
11 

teraz zdefiniować swoją pochodzącą mock klasy, które powinny zastąpić oryginalny dla celów testowych:

package de.scrum_master.aop.mock; 

import de.scrum_master.aop.app.HardWired; 

public class HardWiredMock extends HardWired { 
    public HardWiredMock(int id, String name) { 
     super(id, name); 
    } 

    @Override 
    public void doSomething() { 
     System.out.println("Mocking database values"); 
    } 

    @Override 
    public int getSomething() { 
     return 22; 
    } 

    @Override 
    public String toString() { 
     return "Mocked: " + super.toString(); 
    } 
} 

I wreszcie zdefiniować aspekt z prostego punktu przekroju i radę zastąpić oryginalną wartość podczas każdego wywołania konstruktora:

package de.scrum_master.aop.aspect; 

import de.scrum_master.aop.app.HardWired; 
import de.scrum_master.aop.mock.HardWiredMock; 


public aspect MockInjector { 
    HardWired around(int p1, String p2) : call(HardWired.new(int, String)) && args(p1, p2) { 
     return new HardWiredMock(p1, p2); 
    } 
} 

zmian wyjścia jak życzenia:

Mocked: HardWired [id=999, name=My object] 
Mocking database values 
22 

Robisz które raz na klasę i konstruktora i są w porządku. Aby uogólnić podejście, potrzebne są właściwości joinpoint i, w zależności od tego, jak daleko się posuniesz, może refleksja, ale tutaj jest całkiem prosta. Cieszyć się!

+0

To bardzo szczegółowa odpowiedź, która wydaje się być dokładnie tym, czego szukam. Dzięki! –

+0

Nie tak szybko! Zapomniałem wspomnieć, że aby zastosować to do biblioteki trzeciej strony, musisz wplatać to w kod biblioteki, albo przez LTW albo przez tkanie klas binarnych i zastępowanie biblioteki przez JAR zastępczy. Ta pierwsza jest bardziej dynamiczna, łatwiejsza do wykonania, jeśli żaden menedżer bezpieczeństwa i elementy podpisywania nie powstrzymają od zastąpienia oryginalnego pliku JAR. ;-) – kriegaex

+0

Muszę się przyjrzeć i zobaczyć, co działa najlepiej. W czasie testu mam pełną kontrolę nad hostią JVM i jej środowiskiem. –

Powiązane problemy