2016-04-07 2 views
1

Ich habe eine RouteBuilder Unterklasse, die meine Camel-Routen einrichtet. Es ist von Frühling gebaut. Zunächst sah es so etwas wie diese:Camel: Wie man eine Route bedingt von der Konfiguration baut?

@Override 
public void configure() throws Exception { 
    from(...) 
    .process(...) 
    .to(...) 
} 

Was Ich mag würde, ist ein zusätzliches Endpunkt-Routing auf Konfiguration basierte tun hinzuzufügen. Es gibt eine Eigenschaftendatei, die Spring verwendet, um die RouteBuilder Bean zu erstellen, und eines der Felder, die es festlegt, ist boolean addAnotherEndpoint. Wenn dieser Boolesche Wert wahr ist, möchte ich einen weiteren to hinzufügen. Wenn es falsch ist, möchte ich, dass es auf sein aktuelles Verhalten zurückfällt. So habe ich es dies:

@Override 
public void configure() throws Exception { 
    from(...) 
    .process(...) 
    .to(...) 
    .choice() 
     when(constant(addAnotherEndpoint)).to(...) 
    .endChoice(); 
} 

Während dies scheint das gewünschte Verhalten habe ich Probleme habe für sie zu schreiben Unit-Tests (weil es den Wert von addAnotherEndpoint aus den Eigenschaften ziehen Datei obwohl ich versuche, um es in meinen Tests zu überschreiben). Gibt es einen besseren Weg, damit umzugehen? Wird meine derzeitige Methode unbeabsichtigte Nebenwirkungen haben?

EDIT:

-I-Tests bin mit einer CamelSpringTestSupport Unterklasse (mit JUnit-Tests). In der @Before Methode erstelle ich eine AdviceWithRouteBuilder, die alle Endpunkte durch Mocks ersetzt. In meinem @Test, bin ich versucht, den Wert von addAnotherEndpoint außer Kraft zu setzen, die von der Properties-Datei genommen wird:

@Test 
public void testConditionalRouting() throws Exception { 
    context.start(); 
    MyRouteBuilder routeBuilder = (MyRouteBuilder) applicationContext.getBean("myRouteBuilder"); 
    routeBuilder.setAddAnotherEndpoint(true); 
    getMockEndpoint("myMockEndpoint").expectedMessageCount(1); 
    sendMockMessage(); 
    assertMockEndpointsSatisfied(); 
    context.stop(); 
} 

Es gibt einen entsprechenden Test, der addAnotherEndpoint-false setzt und behauptet, dass 0-Nachrichten empfangen wurden. Das Problem besteht darin, dass das Überschreiben des Werts dieser Variablen nicht funktioniert. Ein Test wird bestanden und der andere schlägt fehl, je nachdem, ob in der Eigenschaftendatei der Wert true oder false lautet. Was dies für mich nahe legt, ist, dass die Route erstellt wird, bevor ich die Einstellung überschreibe (und damit auch bevor der Kontext gestartet wird). Ich habe einen Debugger eingecheckt und die Einstellung ist korrekt überschrieben. Es scheint nur keinen Einfluss zu haben.

EDIT 2:

Aus meiner AdviceWithRouteBuilder:

@Override 
public void configure() throws Exception { 
    replaceFromWith(MOCK_FROM_ENDPOINT); 
    interceptSendToEndpoint(FIRST_TO_ENDPOINT) 
      .skipSendToOriginalEndpoint().to(MOCK_FIRST_TO_ENDPOINT); 
    weaveById(MY_PROCESSOR_ENDPOINT).replace() 
      .to(MOCK_MY_PROCESSOR_ENDPOINT); 
    weaveById(SECOND_TO_ENDPOINT).replace() 
      .to(MOCK_SECOND_TO_ENDPOINT); 
} 

Dies ersetzt jedes EIP mit einem Mock-Endpunkt. Ich habe 4 Tests, die sich auf diese verlassen, und sie scheinen zu funktionieren, wie erwartet, das einzige Problem ist das bedingte Routing.

Abgesehen von JUnit-Annotationen sind die einzigen Annotationen in meiner Testklasse @Override auf isUseAdviceWith() (gibt True zurück) und createApplicationContext(), die einen neuen Spring Application Context zurückgibt.

Ich habe meine Tests ohne context.start() ausgeführt und der einzige, der bestanden hat, war derjenige, der behauptet, dass 0 Nachrichten empfangen wurden (was sinnvoll ist, wenn die Route nicht gestartet wurde). Ich glaube also nicht, dass der Kontext automatisch gestartet wird.

+0

Das sieht für mich sehr normal aus. Ich denke, das einzige Problem wäre die Art, wie Sie es testen. In einer Live-Umgebung sollte diese Route in Ordnung sein. Können Sie mitteilen, wie Sie es testen? Dann können wir das auch beheben. Übrigens wäre es einfacher, wenn Sie einen Filter anstelle von Choice verwenden, der nur eine Bedingung hat. –

+0

Danke für den Vorschlag. Ich verwende eine CamelSpringTestSupport-Unterklasse, um sie zu testen. Ich werde die Frage aktualisieren, um dies zu berücksichtigen. – tytk

+0

Kann ich auch Ihren AdviceWithRouteBuilder-Block sehen? Hat Ihre Testklasse auch Anmerkungen? Kannst du context.start() auch entfernen? vom Anfang Ihrer Tests, und führen Sie sie aus, um zu sehen, ob der Kontext überhaupt automatisch startet? Wenn ja, ist das Problem dort ... –

Antwort

1

Hier ist, was Arbeits endete:

Mein Test war in Ordnung, aber ich hatte zu überdenken, wie ich meine Route aufbaute. Was passierte, war zu der Zeit, als der Frühlingskontext geschaffen wurde, die Route gebaut wurde.Er hat zu diesem Zeitpunkt den Wert addAnotherEndpoint überprüft und darauf basierend die constant gesetzt. Aber boolean ist ein primitiver Wert, was bedeutet, dass er nach Wert übergeben wurde. Warum ist das wichtig? Weil die Funktion constant() die Route einfach auf der Grundlage des Werts dieser Konstante zum Zeitpunkt der Erstellung der Route festlegt. Eine spätere Änderung über Spring hatte keine Auswirkungen, da der Wert bereits gelesen wurde. Was ich tun musste, war ein Objekt als Prädikat passieren zu lassen, damit ich das gleiche Objekt später als Bohne manipulieren konnte.

Auch ich habe von einem choice() zu einem filter() wie vorgeschlagen geändert. Hier ist das fertige Produkt:

@Override 
public void configure() throws Exception { 
    from(...) 
    .process(...) 
    .to(...) 
    .choice() 
     when(myBooleanPredicate).to(...) 
    .endChoice(); 
} 

Und mein benutzerdefiniertes Prädikat, das über Feder manipuliert werden könnte:

public class BooleanPredicate implements Predicate { 
    private boolean value; 

    @Override 
    public boolean matches(Exchange exchange) { 
    return value; 
    } 

    public void setValue(boolean value) { 
    this.value = value; 
    } 

Diese BooleanPredicate ‚s interne value ist auf addAnotherPredicate. Es wird jedes Mal neu gelesen, wenn die Route ausgeführt wird, da BooleanPredicate als Referenz übergeben wird.