แทนที่การตั้งค่าเริ่มต้น Spring-Boot application.properties ใน Junit Test


198

ฉันมีแอปพลิเคชัน Spring-Boot ซึ่งคุณสมบัติเริ่มต้นถูกตั้งค่าในapplication.propertiesไฟล์ใน classpath (src / main / resources / application.properties)

ฉันต้องการแทนที่การตั้งค่าเริ่มต้นบางอย่างในการทดสอบ JUnit ด้วยคุณสมบัติที่ประกาศในtest.propertiesไฟล์ (src / test / resources / test.properties)

ฉันปกติมีชั้นเรียนเฉพาะสำหรับการทดสอบ Junit ของฉันเช่น

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 {

}

ฉันแรกคิดว่าการใช้@PropertySource("classpath:test.properties")ในคลาส TestConfig จะทำเคล็ดลับ แต่คุณสมบัติเหล่านี้จะไม่เขียนทับการตั้งค่า application.properties (ดูเอกสารอ้างอิง Spring-Boot เอกสารอ้างอิง - 23. การกำหนดค่าภายนอก )

จากนั้นฉันพยายามใช้-Dspring.config.location=classpath:test.propertiesเมื่อเรียกใช้การทดสอบ ประสบความสำเร็จ - แต่ฉันไม่ต้องการตั้งค่าคุณสมบัติระบบนี้สำหรับการทดสอบแต่ละครั้ง ดังนั้นฉันใส่ไว้ในรหัส

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

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

}

ซึ่งน่าเสียดายที่ไม่ประสบความสำเร็จอีกครั้ง

จะต้องมีวิธีง่ายๆในการแทนที่application.propertiesการตั้งค่าในการทดสอบ JUnit โดยtest.propertiesที่ฉันต้องมองข้าม


หากคุณต้องการกำหนดค่าเพียงไม่กี่คุณสมบัติคุณสามารถใช้คำอธิบายประกอบ @DynamicPropertySource ใหม่ stackoverflow.com/a/60941845/8650621
Felipe Desiderati

คำตอบ:


293

คุณสามารถใช้เพื่อแทนที่ค่าใน@TestPropertySource application.propertiesจาก javadoc:

แหล่งที่มาของคุณสมบัติการทดสอบสามารถใช้เพื่อเลือกแทนที่คุณสมบัติที่กำหนดในระบบและคุณสมบัติของแอปพลิเคชัน

ตัวอย่างเช่น:

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

}

2
แค่นั้นแหละ. ขอบคุณ โชคไม่ดีที่มันไม่ทำงานเมื่อใช้กับ ExampleApplication.class ดังนั้นฉันจึงต้องตั้งค่ามันในแต่ละคลาสทดสอบ นั่นถูกต้องใช่ไหม?
FrVaBe

1
มันต้องไปที่ไหนซักแห่งในลำดับชั้นของคลาสการทดสอบนั่นคือคุณสามารถใช้ซูเปอร์คลาสทั่วไปเพื่อกำหนดค่าให้กับคลาสการทดสอบที่แตกต่างกันจำนวนหนึ่ง
Andy Wilkinson

64
นอกจากนี้โปรดทราบว่า@TestPropertySourceสามารถยอมรับpropertiesอาร์กิวเมนต์เพื่อเขียนทับคุณสมบัติบางอย่างในบรรทัดเช่น@TestPropertySource(properties = "myConf.myProp=valueInTest")มีประโยชน์ในกรณีที่คุณไม่ต้องการไฟล์คุณสมบัติใหม่ทั้งหมด
dyng

2
คุณสามารถระบุหลายไฟล์ในอาเรย์และยังไฟล์ในระบบไฟล์ (แต่จำไว้ว่าพวกเขาอาจไม่ทำงานบนเซิร์ฟเวอร์ CI):@TestPropertySource(locations={"file:C:/dev/...","classpath:test.properties"})
Adam

8
โปรดทราบว่า@SpringApplicationConfigurationเลิกใช้แล้วและคุณควรใช้@SpringBootTest
mrkernelpanic

74

Spring Boot จะโหลดโดยอัตโนมัติsrc/test/resources/application.propertiesหากมีการใช้คำอธิบายประกอบต่อไปนี้

@RunWith(SpringRunner.class)
@SpringBootTest

ดังนั้นการเปลี่ยนชื่อtest.propertiesเพื่อapplication.propertiesที่จะใช้การตั้งค่าอัตโนมัติ

หากคุณ* เท่านั้น *จำเป็นต้องโหลดไฟล์คุณสมบัติ (ลงในสิ่งแวดล้อม) คุณสามารถใช้สิ่งต่อไปนี้ตามที่อธิบายไว้ที่นี่

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

[ อัปเดต: การเอาชนะคุณสมบัติบางอย่างสำหรับการทดสอบ ]

  1. src/main/resources/application-test.propertiesเพิ่ม
  2. @ActiveProfiles("test")ทดสอบระดับคำอธิบายประกอบกับ

โหลดนี้application.propertiesและจากนั้น application-test.propertiesคุณสมบัติในบริบทพลิเคชันสำหรับกรณีที่ผลการทดสอบเป็นไปตามกฎระเบียบที่กำหนดไว้ที่นี่

การสาธิต - https://github.com/mohnish82/so-spring-boot-testprops


1
ไม่แน่ใจว่าเป็นความคิดที่ดีหรือไม่หากมีสองapplication.propertiesไฟล์ใน classpath (หนึ่งในsrc/main/resourcesและหนึ่งในsrc/test/resources) ใครรับประกันได้ว่าทั้งสองจะต้องดำเนินการและสิ่งที่จะต้องดำเนินการก่อน?
FrVaBe

3
@FrVaBe Spring กำลังจะรับประกัน! คุณสมบัติโปรไฟล์หลักจะโหลดอยู่เสมอ จากนั้นในระหว่างขั้นตอนการทดสอบคุณสมบัติการทดสอบจะถูกโหลดเพิ่ม / แทนที่คุณสมบัติใหม่ / ที่มีอยู่ ถ้าคุณไม่ชอบการรักษาทั้งสองไฟล์ที่มีชื่อเดียวกันแล้วคุณสามารถเพิ่มapplication-test.propertiesในsrc/main/resourcesและระบุtestเป็นรายละเอียดการใช้งานในกรณีที่ผลการทดสอบ
Mohnish

7
สปริงไม่รับประกัน เครื่องมือสร้างจะใช้ทรัพยากรทดสอบเพื่อสนับสนุนทรัพยากรหลักระหว่างการทดสอบ แต่ในกรณีของการทดสอบแอปพลิเคชันคุณสมบัติหลักแอปพลิเคชันคุณสมบัติจะถูกละเว้น นั่นไม่ใช่สิ่งที่ฉันต้องการเพราะหลักมีค่าเริ่มต้นที่มีประโยชน์หลายอย่างและฉันต้องการแทนที่บางอย่างในระหว่างการทดสอบ (และฉันไม่ต้องการทำซ้ำไฟล์ทั้งหมดในส่วนทดสอบ) ดูที่นี่
FrVaBe

6
คุณถูกต้องsrc/test/resources/application.propertiesจะมีการโหลดเฉพาะคุณสมบัติที่กำหนดไว้ในระหว่างขั้นตอนการทดสอบsrc/main/resources/application.propertiesเท่านั้น
Mohnish

11
หากคุณไม่ได้ใช้โปรไฟล์คุณไม่จำเป็นต้องมีโปรไฟล์ "ทดสอบ" เฉพาะ เพียงตั้งชื่อคุณสมบัติการทดสอบของคุณapplication-default.propertiesและพวกเขาจะได้รับการพิจารณาเพราะคุณกำลังเรียกใช้โปรไฟล์ "เริ่มต้น" โดยอัตโนมัติ (หากไม่ได้ประกาศอื่น ๆ )
FrVaBe

65

คุณยังสามารถใช้ข้อมูลกำกับเมตาเพื่อกำหนดค่าภายนอก ตัวอย่างเช่น:

@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 { }

21

วิธีการอื่นที่เหมาะสมสำหรับการเอาชนะคุณสมบัติบางอย่างในการทดสอบของคุณหากคุณใช้@SpringBootTestคำอธิบายประกอบ:

@SpringBootTest(properties = {"propA=valueA", "propB=valueB"})

1
ไม่SpringBootTestโหลดไฟล์ application.properties?
TuGordoBello

8

TLDR:

ดังนั้นสิ่งที่ฉันทำคือการมีมาตรฐานsrc/main/resources/application.propertiesและsrc/test/resources/application-default.propertiesที่ฉันแทนที่การตั้งค่าบางอย่างสำหรับการทดสอบทั้งหมดของฉัน

เรื่องราวทั้งหมด

ฉันพบปัญหาเดียวกันและไม่ได้ใช้โปรไฟล์อย่างใดอย่างหนึ่ง ดูเหมือนว่าจะน่ารำคาญที่ต้องทำตอนนี้และจำประกาศโปรไฟล์ - ซึ่งสามารถลืมได้ง่าย

เคล็ดลับคือเพื่อใช้ประโยชน์จากการapplication-<profile>.propertiesตั้งค่าเฉพาะโปรไฟล์ที่แทนที่ในโปรไฟล์ทั่วไป ดูhttps://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-profile-specific-properties


3

คำอธิบายง่ายๆ:

หากคุณเป็นเช่นฉันและคุณมีเดียวกันapplication.propertiesในsrc/main/resourcesและsrc/test/resourcesและคุณสงสัยว่าทำไมapplication.propertiesในโฟลเดอร์การทดสอบของคุณไม่ได้เอาชนะapplication.propertiesทรัพยากรหลักของคุณอ่านต่อ ...

ถ้าคุณมีapplication.propertiesภายใต้src/main/resourcesและเดียวกันapplication.propertiesภายใต้src/test/resourcesซึ่งapplication.propertiesได้รับเลือกขึ้น, ขึ้นอยู่กับว่าคุณกำลังเรียกใช้การทดสอบของคุณ โฟลเดอร์โครงสร้าง src/main/resourcesและsrc/test/resourcesเป็นสถาปัตยกรรมที่ประชุม Maven ดังนั้นถ้าคุณเรียกใช้การทดสอบของคุณชอบmvnw testหรือแม้กระทั่งgradlew testการapplication.propertiesในการsrc/test/resourcesที่จะได้รับเลือกขึ้นเช่นการทดสอบ classpath จะนำหน้าหลัก classpath แต่ถ้าคุณเรียกใช้การทดสอบของคุณRun as JUnit Testใน Elipse / STS, application.propertiesin src/main/resourcesจะได้รับเลือกเป็นclasspath หลักนำหน้าclasspath ทดสอบ

Run > Run Configurations > JUnit > *your_run_configuration* > Click on "Show Command Line"คุณสามารถตรวจสอบมันออกมาโดยการเปิด

คุณจะเห็นสิ่งที่ชอบ:

XXXbin \ javaw.exe -ea -Dfile.encoding = UTF-8 -classpath XXX \ workspace-spring-tool-suite-4-4.5.1.RELEASE \ project_name \ bin \ main; XXX \ พื้นที่ทำงานฤดูใบไม้ผลิเครื่องมือในตัว-4-4.5.1.RELEASE \ project_name \ bin \ test;

คุณเห็นว่า\ หลักมาก่อนแล้ว\ test ? ใช่มันเกี่ยวกับ classpath :-)

ไชโย


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`

1

หากคุณใช้ Spring 5.2.5 และ Spring Boot 2.2.6 และต้องการแทนที่คุณสมบัติเพียงไม่กี่ไฟล์แทนที่จะเป็นไฟล์ทั้งหมด คุณสามารถใช้คำอธิบายประกอบใหม่: @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);
    }
}

0

มิฉะนั้นเราอาจเปลี่ยนชื่อตัวกำหนดค่าคุณสมบัติเริ่มต้นการตั้งค่าคุณสมบัติspring.config.name=testแล้วมีทรัพยากรคลาสพา ธ src/test/test.propertiesอินสแตนซ์ดั้งเดิมของเราorg.springframework.boot.SpringApplicationจะถูกกำหนดค่าโดยอัตโนมัติจาก test.properties ที่แยกจากกันนี้โดยไม่สนใจคุณสมบัติของแอปพลิเคชัน

ประโยชน์: การกำหนดค่าการทดสอบอัตโนมัติ

ข้อเสียเปรียบ: เปิดเผยคุณสมบัติ "spring.config.name" ที่ชั้น CI

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

spring.config.name = application # ชื่อไฟล์กำหนดค่า


5
การเพิกเฉยapplication.propertiesไม่ใช่ตัวเลือกสำหรับฉันเนื่องจากฉันต้องการแทนที่ค่าการกำหนดค่าดั้งเดิมบางอย่างในการทดสอบ
FrVaBe

ฉันได้รับการมองหาวิธีที่จะมีการทดสอบเดียวที่ไม่ได้โหลด src / main / resources / application.properties และนี่คือมัน สร้างไฟล์: src / test / resources / empty.properties และเพิ่มคำอธิบายประกอบในการทดสอบที่ควรละเว้นคุณสมบัติหลัก @TestPropertySource (properties = "spring.config.name = empty")
rvertigo

วิธีการตั้งค่าคุณสมบัติเฉพาะสำหรับวิธีทดสอบ Junit แต่ละวิธี?
Nicolas

0

คุณยังสามารถสร้างไฟล์ application.properties ใน src / test / resources ที่ JUnits ของคุณถูกเขียน


สิ่งนี้ช่วยได้อย่างไร? ^^
jumping_monkey
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.