Spring Boot @ConfigurationProperties testen

1. Overzicht

In onze vorige gids voor @ConfigurationProperties, we hebben geleerd hoe we de @ConfigurationProperties annotatie met Spring Boot voor het werken met externe configuratie.

In deze tutorial we laten zien hoe configuratieklassen kunnen worden getest die afhankelijk zijn van het @ConfigurationProperties annotatie om ervoor te zorgen dat onze configuratiegegevens correct worden geladen en aan de bijbehorende velden zijn gekoppeld.

2. Afhankelijkheden

In ons Maven-project gebruiken we de spring-boot-starter en spring-boot-starter-test afhankelijkheden om respectievelijk de core spring API en Spring's test API in te schakelen:

 org.springframework.boot spring-boot-starter-parent 2.2.2.RELEASE org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-test test 

Laten we ook ons ​​project configureren met afhankelijkheden van bean-validatie, aangezien we ze later zullen gebruiken:

  org.hibernate slaapstand-validator javax.el javax.el-api 3.0.0 org.glassfish.web javax.el 2.2.6 

3. Eigenschappen die binden aan door de gebruiker gedefinieerde POJO's

Bij het werken met een externe configuratie, we maken doorgaans POJO's met velden die overeenkomen met de overeenkomende configuratie-eigenschappen. Zoals we al weten, zal Spring vervolgens automatisch de configuratie-eigenschappen binden aan de Java-klassen die we maken.

Laten we om te beginnen aannemen dat we een serverconfiguratie hebben in een eigenschappenbestand dat we zullen aanroepen src / test / resources / server-config-test.properties:

server.address.ip = 192.168.0.1 server.resources_path.imgs = / root / imgs

Laten we nu een eenvoudige configuratieklasse definiëren die overeenkomt met het vorige eigenschappenbestand:

@Configuration @ConfigurationProperties (prefix = "server") openbare klasse ServerConfig {privé adresadres; private Map resourcesPath; // getters en setters}

en ook de bijbehorende Adres type:

openbare klasse Adres {privé String ip; // getters en setters}

Laten we tot slot de Serverconfiguratie POJO in onze testklasse en valideer dat al zijn velden correct zijn ingesteld:

@ExtendWith (SpringExtension.class) @EnableConfigurationProperties (waarde = ServerConfig.class) @TestPropertySource ("classpath: server-config-test.properties") openbare klasse BindingPropertiesToUserDefinedPOJOUnitTest {@Autowired serverConfigonfigonfigonfigonfig; @Test ongeldig gegevenUserDefinedPOJO_whenBindingPropertiesFile_thenAllFieldsAreSet () {assertEquals ("192.168.0.1", serverConfig.getAddress (). GetIp ()); Kaart verwachteResourcesPath = nieuwe HashMap (); verwachteResourcesPath.put ("imgs", "/ root / imgs"); assertEquals (verwachtResourcesPath, serverConfig.getResourcesPath ()); }}

In deze test hebben we de volgende annotaties gebruikt:

  • @ExtendWith - integreert Spring's TestContext-framework met JUnit5
  • @EnableConfigurationProperties - maakt ondersteuning mogelijk voor @ConfigurationProperties bonen (in dit geval de Serverconfiguratie Boon)
  • @TestPropertySource - specificeert een testbestand dat de standaard overschrijft application.properties het dossier

4. @ConfigurationProperties Aan @Boon Methoden

Een andere manier om configuratiebeans te maken, is door de @ConfigurationProperties annotatie op @Boon methoden.

Bijvoorbeeld de volgende getDefaultConfigs () methode creëert een Serverconfiguratie configuratie bean:

@Configuration publieke klasse ServerConfigFactory {@Bean (name = "default_bean") @ConfigurationProperties (prefix = "server.default") public ServerConfig getDefaultConfigs () {retourneer nieuwe ServerConfig (); }}

Zoals we kunnen zien, kunnen we het Serverconfiguratie instantie met behulp van @ConfigurationProperties op de getDefaultConfigs () methode, zonder de Serverconfiguratie klasse zelf. Dit kan met name handig zijn wanneer u werkt met een externe klasse van derden die beperkte toegang heeft.

Laten we vervolgens een voorbeeld van een externe eigenschap definiëren:

server.default.address.ip = 192.168.0.2

Ten slotte, om Spring te vertellen om de ServerConfigFactory class bij het laden van de ApplicationContext (dus maak onze configuratieboon aan), we zullen de @ContextConfiguration annotatie bij de testklasse:

@ExtendWith (SpringExtension.class) @EnableConfigurationProperties (waarde = ServerConfig.class) @ContextConfiguration (classes = ServerConfigFactory.class) @TestPropertySource ("classpath: server-config-test.properties") openbare klasse BindingPropertySource (@BindingPropertySource) default_bean ") private ServerConfig serverConfig; @Test ongeldig gegevenBeanAnnotatedMethod_whenBindingProperties_thenAllFieldsAreSet () {assertEquals ("192.168.0.2", serverConfig.getAddress (). GetIp ()); // andere beweringen ...}}

5. Validatie van eigenschappen

Om bean-validatie in Spring Boot in te schakelen, we moeten de klasse op het hoogste niveau annoteren met @Gevalideerd. Vervolgens voegen we het vereiste toe javax.validation beperkingen:

@Configuration @ConfigurationProperties (prefix = "validate") @Gevalideerde public class mailserver {@NotNull @NotEmpty private Map propertiesMap; @Valid privé MailConfig mailConfig = nieuwe MailConfig (); // getters en setters}

Evenzo is het MailConfig klasse heeft ook enkele beperkingen:

openbare klasse MailConfig {@NotBlank @Email privé String-adres; // getters en setters}

Door een geldige dataset te verstrekken:

validate.propertiesMap.first = prop1 validate.propertiesMap.second = prop2 [e-mail beveiligd]

de applicatie start normaal en onze unit tests zullen slagen voor:

@ExtendWith (SpringExtension.class) @EnableConfigurationProperties (waarde = MailServer.class) @TestPropertySource ("classpath: property-validation-test.properties") publieke klasse PropertyValidationUnitTest {@Autowired private MailServer mailServer; privé statische Validator propertyValidator; @BeforeAll openbare statische ongeldige setup () {propertyValidator = Validation.buildDefaultValidatorFactory (). GetValidator (); } @Test ongeldig whenBindingPropertiesToValidatedBeans_thenConstrainsAreChecked () {assertEquals (0, propertyValidator.validate (mailServer.getPropertiesMap ()). Size ()); assertEquals (0, propertyValidator.validate (mailServer.getMailConfig ()). size ()); }}

Aan de andere kant, als we ongeldige eigenschappen gebruiken, zal Spring een IllegalStateException in de beginfase.

Gebruik bijvoorbeeld een van deze ongeldige configuraties:

validate.propertiesMap.second = validate.mail_config.address = user1.test

zal ervoor zorgen dat onze applicatie mislukt, met deze foutmelding:

Eigenschap: validate.propertiesMap [tweede] Waarde: Reden: mag niet leeg zijn Eigenschap: validate.mailConfig.address Waarde: user1.test Reden: moet een correct e-mailadres zijn

Let erop dat we hebben gebruikt @Geldig op de mailConfig veld om ervoor te zorgen dat het MailConfig beperkingen worden gecontroleerd, zelfs als validate.mailConfig.address was niet gedefinieerd. Anders zou de lente onder gaan mailConfig naar nul en start de applicatie normaal.

6. Conversie van eigenschappen

Spring Boot-eigenschappenconversie stelt ons in staat om sommige eigenschappen in specifieke typen om te zetten.

In dit gedeelte beginnen we met het testen van configuratieklassen die gebruikmaken van de ingebouwde conversie van Spring. Vervolgens testen we een aangepaste converter die we zelf maken.

6.1. Spring Boot's standaardconversie

Laten we eens kijken naar de volgende eigenschappen voor gegevensgrootte en duur:

# gegevensgrootten convert.upload_speed = 500 MB convert.download_speed = 10 # duur convert.backup_day = 1d convert.backup_hour = 8

Spring Boot zal deze eigenschappen automatisch aan de overeenkomst binden DataSize en Looptijd velden gedefinieerd in de PropertyConversion configuratie klasse:

@Configuration @ConfigurationProperties (prefix = "convert") openbare klasse PropertyConversion {privé DataSize uploadSpeed; @DataSizeUnit (DataUnit.GIGABYTES) privé DataSize downloadSpeed; privé Duur backupDag; @DurationUnit (ChronoUnit.HOURS) privé Duur backupHour; // getters en setters}

Laten we nu de conversieresultaten bekijken:

@ExtendWith (SpringExtension.class) @EnableConfigurationProperties (waarde = PropertyConversion.class) @ContextConfiguration (classes = CustomCredentialsConverter.class) @TestPropertySource ("classpath: spring-conversion-test.properties") public class SpringProperties property; public class SpringProperties @Test ongeldig whenUsingSpringDefaultSizeConversion_thenDataSizeObjectIsSet () {assertEquals (DataSize.ofMegabytes (500), propertyConversion.getUploadSpeed ​​()); assertEquals (DataSize.ofGigabytes (10), propertyConversion.getDownloadSpeed ​​()); } @Test ongeldig whenUsingSpringDefaultDurationConversion_thenDurationObjectIsSet () {assertEquals (Duration.ofDays (1), propertyConversion.getBackupDay ()); assertEquals (Duration.ofHours (8), propertyConversion.getBackupHour ()); }}

6.2. Aangepaste converters

Laten we ons nu eens voorstellen dat we de convert.referenties eigendom:

convert.credentials = gebruiker, 123

in het volgende Referentie klasse:

public class Credentials {private String gebruikersnaam; privé String-wachtwoord; // getters en setters}

Om dit te bereiken, kunnen we een aangepaste converter implementeren:

@Component @ConfigurationPropertiesBinding public class CustomCredentialsConverter implementeert Converter {@Override public credentials convert (String source) {String [] data = source.split (","); nieuwe inloggegevens retourneren (data [0], data [1]); }}

Laten we tot slot een Inloggegevens veld naar het PropertyConversion klasse:

openbare klasse PropertyConversion {privéreferenties inloggegevens; // ...}

In onze SpringPropertiesConversionUnitTest testklasse, we moeten ook toevoegen @ContextConfiguration om de aangepaste converter in de context van Spring te registreren:

// andere annotaties @ContextConfiguration (classes = CustomCredentialsConverter.class) openbare klasse SpringPropertiesConversionUnitTest {// ... @Test void whenRegisteringCustomCredentialsConverter_thenCredentialsAreParsed () {assertEquals ("user", property). assertEquals ("123", propertyConversion.getCredentials (). getPassword ()); }}

Zoals de vorige beweringen laten zien, Spring heeft onze aangepaste converter gebruikt om het convert.referenties eigendom in een Inloggegevens voorbeeld.

7. YAML-documenten bindend

Voor hiërarchische configuratiegegevens kan de YAML-configuratie handiger zijn. Bovendien ondersteunt YAML het definiëren van meerdere profielen binnen hetzelfde document.

Het volgende application.yml gelegen onder src / test / resources / definieert een "test" -profiel voor de Serverconfiguratie klasse:

spring: profielen: testserver: adres: ip: 192.168.0.4 resources_path: imgs: / etc / test / imgs --- # andere profielen

Als resultaat zal de volgende test slagen:

@ExtendWith (SpringExtension.class) @ContextConfiguration (initializers = ConfigFileApplicationContextInitializer.class) @EnableConfigurationProperties (waarde = ServerConfig.class) @ActiveProfiles ("test") openbare klasse BindingYMLPropertiesUnitfig serverConfigonfigonfig; @Test ongeldig whenBindingYMLConfigFile_thenAllFieldsAreSet () {assertEquals ("192.168.0.4", serverConfig.getAddress (). GetIp ()); // andere beweringen ...}}

Een paar opmerkingen over de gebruikte annotaties:

  • @ContextConfiguration (initializers = ConfigFileApplicationContextInitializer.class) - laadt het application.yml het dossier
  • @ActiveProfiles ("test") - geeft aan dat het “test” -profiel zal worden gebruikt tijdens deze test

Laten we tot slot dat in gedachten houden geen van beide @ProperySource noch @TestProperySource ondersteuning laden .yml bestanden. Daarom moeten we onze YAML-configuraties altijd binnen het application.yml het dossier.

8. Overschrijven @ConfigurationProperties Configuraties

Soms willen we configuratie-eigenschappen die zijn geladen door @ConfigurationProperties met een andere dataset, vooral bij het testen.

Zoals we in eerdere voorbeelden hebben laten zien, kunnen we gebruiken @TestPropertySource ("path_to_new_data_set") om de hele originele configuratie te vervangen (onder / src / main / resources) met een nieuwe.

Als alternatief kunnen we selectief enkele van de oorspronkelijke eigenschappen vervangen met behulp van de eigendommen kenmerk van @TestPropertySource ook.

Stel dat we het eerder gedefinieerde willen overschrijven validate.mail_config.address onroerend goed met een andere waarde. Het enige wat we hoeven te doen is onze testles te annoteren met @TestPropertySource en wijs vervolgens een nieuwe waarde toe aan dezelfde eigenschap via de eigendommen lijst:

@TestPropertySource (properties = {"[email protected]"})

Daarom gebruikt Spring de nieuw gedefinieerde waarde:

assertEquals ("[e-mail beveiligd]", mailServer.getMailConfig (). getAddress ());

9. Conclusie

In deze zelfstudie hebben we gezien hoe u verschillende soorten configuratieklassen kunt testen die gebruikmaken van de @ConfigurationProperties annotatie om te laden .eigendommen en .yml configuratiebestanden.

Zoals gewoonlijk is de broncode voor dit artikel beschikbaar op GitHub.