Wie werden Umgebungsvariablen oder Systemeigenschaften in Frühlingstests festgelegt?

93

Ich möchte einige Tests schreiben, die die XML Spring-Konfiguration einer bereitgestellten WAR überprüfen. Leider erfordern einige Beans, dass einige Umgebungsvariablen oder Systemeigenschaften festgelegt werden. Wie kann ich eine Umgebungsvariable festlegen, bevor die Spring Beans initialisiert werden, wenn der praktische Teststil mit @ContextConfiguration verwendet wird?

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:whereever/context.xml")
public class TestWarSpringContext { ... }

Wenn ich den Anwendungskontext mit Anmerkungen konfiguriere, wird kein Hook angezeigt, an dem ich etwas tun kann, bevor der Frühlingskontext initialisiert wird.

Hans-Peter Störr
quelle

Antworten:

127

Sie können die System-Eigenschaft in einem statischen Initialisierer initialisieren:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:whereever/context.xml")
public class TestWarSpringContext {

    static {
        System.setProperty("myproperty", "foo");
    }

}

Der statische Initialisierungscode wird ausgeführt, bevor der Spring-Anwendungskontext initialisiert wird.

Jimmy Praet
quelle
14
Blöd mich - OK, das würde funktionieren. Noch besser: Wahrscheinlich würde auch eine @BeforeClassMethode zum Festlegen der Systemeigenschaft und eine @AfterClassMethode zum Entfernen der Systemeigenschaft funktionieren und nach sich selbst aufräumen. (Ich habe es aber nicht ausprobiert.)
Hans-Peter Störr
1
Versuchte die @BeforeClass - und es funktionierte gut zum Festlegen von Systemeigenschaften, bevor andere Eigenschaften in der Testinstanz festgelegt wurden
wbdarby
Danke dafür. Die statische Sache hat nicht funktioniert, aber eine kleine Methode mit @BeforeClass hat funktioniert!
Midhun Agnihotram
Dieser Mechanismus funktioniert nicht, wenn die Eigenschaft der Log4j2-Konfigurationsdatei geändert wird. Es scheint, dass Spring ohnehin vor diesem statischen Code geladen wird (und daher falsch protokolliert).
Lucasvc
86

Der richtige Weg, dies ab Spring 4.1 zu tun, ist die Verwendung einer @TestPropertySourceAnmerkung.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:whereever/context.xml")
@TestPropertySource(properties = {"myproperty = foo"})
public class TestWarSpringContext {
    ...    
}

Siehe @TestPropertySource in den Spring-Dokumenten und Javadocs .

Raman
quelle
2
Diese Anmerkung unterstützt auch einen Eigenschaftendateipfad.
MigDus
2
Ich könnte das Spring Cloud Config Client-Label während der Tests mit@TestPropertySource(properties={"spring.cloud.config.label=feature/branch"})
Marcello de Sales
4
Gute Antwort, aber leider nicht für mich funktioniert, mit Spring 4.2.9 war die Eigenschaft immer leer. Nur der statische Block funktionierte ... Funktionierte für Anwendungseigenschaften, jedoch nicht für Systemeigenschaften.
Gregor
Zuerst habe ich die statische Version gesehen und ausprobiert (die funktioniert hat), aber diese Anmerkung ist noch sauberer und viel besser (für mich, da sie auch wie ein Zauber funktioniert).
BAERUS
3
Dies stellt eine EnvironmentEigenschaft bereit , die sich von einer "Umgebungsvariablen" unterscheidet.
OrangeDog
11

Sie können auch einen Test ApplicationContextInitializer verwenden, um eine Systemeigenschaft zu initialisieren:

public class TestApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>
{
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext)
    {
        System.setProperty("myproperty", "value");
    }
}

und konfigurieren Sie es dann in der Testklasse zusätzlich zu den Speicherorten der Spring-Kontextkonfigurationsdatei:

@ContextConfiguration(initializers = TestApplicationContextInitializer.class, locations = "classpath:whereever/context.xml", ...)
@RunWith(SpringJUnit4ClassRunner.class)
public class SomeTest
{
...
}

Auf diese Weise kann eine Codeduplizierung vermieden werden, wenn für alle Komponententests eine bestimmte Systemeigenschaft festgelegt werden soll.

anre
quelle
Dies funktioniert auch perfekt mit Spring Boot 2.x und Junit 5.x (unter Verwendung @SpringBootTestoder einer der Test-Slicing- Annotationen)
Wim Deblauwe
9

Alle Antworten hier beziehen sich derzeit nur auf die Systemeigenschaften, die sich von den Umgebungsvariablen unterscheiden, deren Festlegung komplexer ist, insbesondere für Tests. Zum Glück kann die folgende Klasse dafür verwendet werden, und die Klassendokumente enthalten gute Beispiele

EnvironmentVariables.html

Ein kurzes Beispiel aus den Dokumenten, das für die Arbeit mit @SpringBootTest geändert wurde

@SpringBootTest
public class EnvironmentVariablesTest {
   @ClassRule
   public final EnvironmentVariables environmentVariables = new EnvironmentVariables().set("name", "value");

   @Test
   public void test() {
     assertEquals("value", System.getenv("name"));
   }
 }
Harish Gokavarapu
quelle
Die EnvironmentVariables-Regeln sind Teil einer Drittanbieter-Bibliothek, verwenden Hacky Reflection, um die zwischengespeicherten Werte der Umgebung im JVM-Speicher zu ändern, und berücksichtigen nicht einmal die tatsächlichen Umgebungsvariablen. Daher möchte ich es nicht verwenden oder jemandem empfehlen, dies zu tun.
Christian
4

Wenn Sie möchten, dass Ihre Variablen für alle Tests gültig sind, können Sie eine application.propertiesDatei in Ihrem Testressourcenverzeichnis haben (standardmäßig :), src/test/resourcesdie ungefähr so ​​aussieht:

MYPROPERTY=foo

Diese wird dann geladen und verwendet, es sei denn, Sie haben Definitionen über @TestPropertySourceoder eine ähnliche Methode. Die genaue Reihenfolge, in der die Eigenschaften geladen werden, finden Sie in der Spring-Dokumentation, Kapitel 24. Externalisierte Konfiguration .

blalasaadri
quelle
2

Sie können die Systemeigenschaften als VM-Argumente festlegen.

Wenn Ihr Projekt ein Maven-Projekt ist, können Sie beim Ausführen der Testklasse den folgenden Befehl ausführen:

mvn test -Dapp.url="https://stackoverflow.com"

Testklasse:

public class AppTest  {
@Test
public void testUrl() {
    System.out.println(System.getProperty("app.url"));
    }
}

Wenn Sie eine einzelne Testklasse oder -methode in Eclipse ausführen möchten, gehen Sie wie folgt vor:

1) Gehen Sie zu Ausführen -> Konfiguration ausführen

2) Wählen Sie auf der linken Seite Ihre Testklasse im Abschnitt Junit aus.

3) Gehen Sie wie folgt vor:

Geben Sie hier die Bildbeschreibung ein

Joby Wilson Mathews
quelle
1

Bei Komponententests wird die Systemvariable noch nicht instanziiert, wenn ich "mvn clean install" durchführe, da auf keinem Server die Anwendung ausgeführt wird. Um die Systemeigenschaften festzulegen, muss ich dies in pom.xml tun. Wie so:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.21.0</version>
    <configuration>
        <systemPropertyVariables>
            <propertyName>propertyValue</propertyName>
            <MY_ENV_VAR>newValue</MY_ENV_VAR>
            <ENV_TARGET>olqa</ENV_TARGET>
            <buildDirectory>${project.build.directory}</buildDirectory>
        </systemPropertyVariables>
    </configuration>
</plugin>
Gen
quelle