Mengesampingkan pengaturan default Spring-Boot application.properties di Junit Test

198

Saya memiliki aplikasi Spring-Boot di mana properti default diatur dalam application.propertiesfile di classpath (src / main / resources / application.properties).

Saya ingin mengganti beberapa pengaturan default dalam uji JUnit saya dengan properti yang dideklarasikan dalam test.propertiesfile (src / test / resources / test.properties)

Saya biasanya memiliki Kelas Konfigurasi khusus untuk Tes Junit saya, misalnya

package foo.bar.test;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(CoreConfig.class)
@EnableAutoConfiguration
public class TestConfig {

}

Saya pertama kali berpikir bahwa menggunakan @PropertySource("classpath:test.properties")di kelas TestConfig akan melakukan trik, tetapi properti ini tidak akan menimpa pengaturan application.properties (lihat Spring-Boot Reference Doc - 23. Konfigurasi Eksternalisasi ).

Kemudian saya mencoba menggunakan -Dspring.config.location=classpath:test.propertiesketika menjalankan tes. Itu berhasil - tetapi saya tidak ingin mengatur properti sistem ini untuk setiap eksekusi tes. Jadi saya memasukkannya ke dalam kode

@Configuration
@Import(CoreConfig.class)
@EnableAutoConfiguration
public class TestConfig {

  static {
    System.setProperty("spring.config.location", "classpath:test.properties");
  }

}

yang sayangnya sekali lagi tidak berhasil.

Pasti ada solusi sederhana tentang cara mengesampingkan application.propertiespengaturan dalam tes JUnit dengan test.propertiesyang harus saya abaikan.

FrVaBe
sumber
Jika Anda hanya perlu mengkonfigurasi beberapa properti, Anda dapat menggunakan anotasi @DynamicPropertySource baru. stackoverflow.com/a/60941845/8650621
Felipe Desiderati

Jawaban:

293

Anda dapat menggunakan @TestPropertySourceuntuk mengganti nilai di application.properties. Dari javadoc-nya:

sumber properti uji dapat digunakan untuk menimpa secara selektif properti yang didefinisikan dalam sumber properti sistem dan aplikasi

Sebagai contoh:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ExampleApplication.class)
@TestPropertySource(locations="classpath:test.properties")
public class ExampleApplicationTests {

}
Andy Wilkinson
sumber
2
Itu dia. Terima kasih. Sayangnya itu tidak berfungsi ketika digunakan pada ExampleApplication.class jadi saya harus mengaturnya di setiap kelas tes. Apakah itu benar?
FrVaBe
1
Itu harus pergi ke suatu tempat dalam hirarki kelas tes, yaitu Anda dapat menggunakan superclass umum untuk mengkonfigurasinya di sejumlah kelas uji yang berbeda.
Andy Wilkinson
64
Perhatikan juga bahwa @TestPropertySourcedapat menerima propertiesargumen untuk menimpa beberapa properti inline, seperti @TestPropertySource(properties = "myConf.myProp=valueInTest"), itu berguna jika Anda tidak ingin file properti yang benar-benar baru.
dyng
2
Anda dapat menentukan beberapa file dalam array, dan juga file pada sistem file (tapi ingat mereka mungkin tidak bekerja pada server CI):@TestPropertySource(locations={"file:C:/dev/...","classpath:test.properties"})
Adam
8
Catatan, itu @SpringApplicationConfigurationsudah usang, dan Anda harus menggunakan@SpringBootTest
mrkernelpanic
74

Spring Boot otomatis dimuat src/test/resources/application.properties, jika anotasi berikut digunakan

@RunWith(SpringRunner.class)
@SpringBootTest

Jadi, mengubah nama test.propertiesuntuk application.propertiesmemanfaatkan konfigurasi otomatis.

Jika Anda * hanya * perlu memuat file properti (ke Lingkungan) Anda juga dapat menggunakan yang berikut, seperti yang dijelaskan di sini

@RunWith(SpringRunner.class)
@ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class) 

[ Pembaruan: Mengganti properti tertentu untuk pengujian ]

  1. Tambah src/main/resources/application-test.properties.
  2. Beri anotasi pada kelas tes dengan @ActiveProfiles("test").

Ini memuat application.propertiesdan kemudian application-test.properties properti ke dalam konteks aplikasi untuk kasus uji, sesuai aturan yang ditetapkan di sini .

Demo - https://github.com/mohnish82/so-spring-boot-testprops

Mohnish
sumber
1
Tidak yakin apakah memiliki dua application.propertiesfile di classpath (satu masuk src/main/resourcesdan satu masuk src/test/resources). Siapa yang menjamin bahwa keduanya akan diambil dan mana yang akan diambil lebih dulu?
FrVaBe
3
@FrVaBe Spring akan menjaminnya! Properti profil utama selalu dimuat. Kemudian selama fase uji, properti uji dimuat, menambahkan / mengganti properti baru / yang sudah ada. Jika Anda tidak seperti menjaga dua file dengan nama yang sama, maka Anda dapat menambahkan application-test.propertiesdalam src/main/resourcesdan menentukan testsebagai profil aktif dalam kasus uji.
Mohnish
7
Musim semi tidak memberikan jaminan. Alat bangun akan menggunakan sumber daya uji yang mendukung sumber daya utama selama pengujian. Tetapi dalam kasus aplikasi uji. Properti aplikasi utama. Properti akan diabaikan. Itu bukan yang saya inginkan karena yang utama berisi beberapa nilai default yang berguna dan saya hanya perlu menimpa beberapa dari mereka selama pengujian (dan saya tidak ingin menduplikasi seluruh file di bagian tes). Lihat di sini .
FrVaBe
6
Anda benar, hanya properti yang didefinisikan src/test/resources/application.propertiesyang dimuat selama fase pengujian, src/main/resources/application.propertiesyang diabaikan.
Mohnish
11
Jika Anda tidak menggunakan profil sejauh ini, Anda tidak memerlukan profil "tes" khusus. Cukup beri nama properti pengujian Anda application-default.propertiesdan itu akan dipertimbangkan karena Anda secara otomatis menjalankan profil "default" (jika tidak dinyatakan lainnya).
FrVaBe
65

Anda juga dapat menggunakan meta-anotasi untuk mengeksternalisasi konfigurasi. Sebagai contoh:

@RunWith(SpringJUnit4ClassRunner.class)
@DefaultTestAnnotations
public class ExampleApplicationTests { 
   ...
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@SpringApplicationConfiguration(classes = ExampleApplication.class)
@TestPropertySource(locations="classpath:test.properties")
public @interface DefaultTestAnnotations { }
Rob Winch
sumber
21

Pendekatan lain yang cocok untuk mengganti beberapa properti dalam pengujian Anda, jika Anda menggunakan @SpringBootTestanotasi:

@SpringBootTest(properties = {"propA=valueA", "propB=valueB"})
NimaAJ
sumber
1
Apakah SpringBootTestmemuat file application.properties?
TuGordoBello
8

TLDR:

Jadi apa yang saya lakukan adalah memiliki standar src/main/resources/application.propertiesdan juga src/test/resources/application-default.propertiestempat saya menimpa beberapa pengaturan untuk SEMUA tes saya.

Seluruh cerita

Saya mengalami masalah yang sama dan sejauh ini tidak menggunakan profil. Tampaknya merepotkan harus melakukannya sekarang dan ingat menyatakan profil - yang dapat dengan mudah dilupakan.

Kuncinya adalah, untuk meningkatkan bahwa profil tertentu application-<profile>.propertiesmenimpa pengaturan di profil umum. Lihat https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-profile-specific-properties .

elonderin
sumber
3

Penjelasan sederhana:

Jika Anda seperti saya dan Anda memiliki yang sama application.propertiesdi src/main/resourcesdan src/test/resources, dan Anda bertanya-tanya mengapa application.propertiesdi folder tes Anda tidak mengesampingkan para application.propertiessumber daya utama Anda, baca terus ...

Jika Anda memiliki di application.propertiesbawah src/main/resourcesdan di application.propertiesbawah yang sama src/test/resources, yang application.propertiesdiambil, tergantung pada bagaimana Anda menjalankan tes Anda . Struktur folder src/main/resourcesdan src/test/resources, adalah konvensi arsitektur Maven, jadi jika Anda menjalankan tes seperti mvnw testatau bahkan gradlew test, application.propertiesin src/test/resourcesakan dijemput, karena test classpath akan mendahului classpath utama . Tetapi, jika Anda menjalankan tes Anda seperti Run as JUnit Testdi Elipse / STS, application.propertiesin src/main/resourcesakan dijemput, karena jalur utama utama mendahului jalur kelas uji .

Anda dapat memeriksanya dengan membuka Run > Run Configurations > JUnit > *your_run_configuration* > Click on "Show Command Line".

Anda akan melihat sesuatu seperti:

XXXbin \ javaw.exe -ea -Dfile.encoding = UTF-8 -classpath XXX \ workspace-spring-tool-suite-4-4.5.1.RELEASE \ project_name \ bin \ main; XXX \ workspace-spring-tool-suite-4-4.5.1.RELEASE \ project_name \ bin \ test;

Apakah Anda melihat bahwa \ main terlebih dahulu, lalu \ test ? Benar, Ini semua tentang classpath :-)

Bersulang

jumping_monkey
sumber
1
I just configured min as the following :

spring.h2.console.enabled=true
spring.h2.console.path=/h2-console


# changing the name of my data base for testing
spring.datasource.url= jdbc:h2:mem:mockedDB
spring.datasource.username=sa
spring.datasource.password=sa



# in testing i don`t need to know the port

#Feature that determines what happens when no accessors are found for a type
#(and there are no annotations to indicate it is meant to be serialized).
spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false`enter code here`
Hilal Aissani
sumber
1

Jika Anda menggunakan Spring 5.2.5 dan Spring Boot 2.2.6 dan ingin mengganti hanya beberapa properti alih-alih seluruh file. Anda dapat menggunakan anotasi baru: @DynamicPropertySource

@SpringBootTest
@Testcontainers
class ExampleIntegrationTests {

    @Container
    static Neo4jContainer<?> neo4j = new Neo4jContainer<>();

    @DynamicPropertySource
    static void neo4jProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.data.neo4j.uri", neo4j::getBoltUrl);
    }
}
Felipe Desiderati
sumber
0

Kalau tidak, kita dapat mengubah nama konfigurator properti default, mengatur properti spring.config.name=testdan kemudian memiliki sumber daya kelas-jalur src/test/test.propertiesinstance asli kita org.springframework.boot.SpringApplicationakan secara otomatis dikonfigurasi dari properti test.prop terpisah ini, mengabaikan properti aplikasi;

Manfaat: konfigurasi otomatis pengujian;

Kelemahan: memperlihatkan properti "spring.config.name" di layer CI

ref: http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

spring.config.name = application # Config nama file

D. Soloviev
sumber
5
Mengabaikan application.propertiesbukanlah pilihan bagi saya karena saya hanya ingin mengganti beberapa nilai konfigurasi asli dalam pengujian.
FrVaBe
Saya telah mencari cara untuk memiliki satu tes yang tidak memuat properti src / main / resources / application.prop dan ini dia. Buat file: src / test / resources / empty.properties dan tambahkan anotasi pada tes yang seharusnya mengabaikan properti utama. @TestPropertySource (properties = "spring.config.name = empty")
rvertigo
Bagaimana cara menetapkan nilai properti spesifik untuk setiap metode uji junit?
Nicolas
0

Anda juga dapat membuat file application.properties di src / test / resources di mana JUnits Anda ditulis.

PragmaticFire
sumber
Bagaimana ini membantu? ^^
jumping_monkey