The @DefaultLocale
and @DefaultTimeZone
annotations can be used to change the values returned from Locale.getDefault()
and TimeZone.getDefault()
, respectively, which are often used implicitly when no specific locale or time zone is chosen.
Both annotations work on the test class level and on the test method level, and are inherited from higher-level containers.
After the annotated element has been executed, the initial default value is restored.
@DefaultLocale
The default Locale
can be specified using an IETF BCP 47 language tag string
@Test
@DefaultLocale("zh-Hant-TW")
void test_with_language() {
assertThat(Locale.getDefault()).isEqualTo(Locale.forLanguageTag("zh-Hant-TW"));
}
Alternatively the default Locale
can be created using the following attributes of which a Locale Builder can create an instance with:
-
language
or -
language
andcountry
or -
language
,country
, andvariant
Note
|
The variant needs to be a string which follows the IETF BCP 47 / RFC 5646 syntax! |
@Test
@DefaultLocale(language = "en")
void test_with_language_only() {
assertThat(Locale.getDefault()).isEqualTo(new Locale.Builder().setLanguage("en").build());
}
@Test
@DefaultLocale(language = "en", country = "EN")
void test_with_language_and_country() {
assertThat(Locale.getDefault()).isEqualTo(new Locale.Builder().setLanguage("en").setRegion("EN").build());
}
@Test
@DefaultLocale(language = "ja", country = "JP", variant = "japanese")
void test_with_language_and_country_and_vairant() {
assertThat(Locale.getDefault())
.isEqualTo(new Locale.Builder().setLanguage("ja").setRegion("JP").setVariant("japanese").build());
}
Note that mixing language tag configuration and constructor based configuration will cause an ExtensionConfigurationException
to be thrown.
Furthermore, a variant
can only be specified if country
is also specified.
If variant
is specified without country
, an ExtensionConfigurationException
will be thrown.
Any method level @DefaultLocale
configurations will override class level configurations.
@DefaultLocale(language = "fr")
class MyLocaleTests {
@Test
void test_with_class_level_configuration() {
assertThat(Locale.getDefault()).isEqualTo(new Locale.Builder().setLanguage("fr").build());
}
@Test
@DefaultLocale(language = "en")
void test_with_method_level_configuration() {
assertThat(Locale.getDefault()).isEqualTo(new Locale.Builder().setLanguage("en").build());
}
}
Note
|
A class-level configuration means that the specified locale is set before and reset after each individual test in the annotated class. |
@DefaultTimeZone
The default TimeZone
is specified according to the TimeZone.getTimeZone(String) method.
@Test
@DefaultTimeZone("CET")
void test_with_short_zone_id() {
assertThat(TimeZone.getDefault()).isEqualTo(TimeZone.getTimeZone("CET"));
}
@Test
@DefaultTimeZone("Africa/Juba")
void test_with_long_zone_id() {
assertThat(TimeZone.getDefault()).isEqualTo(TimeZone.getTimeZone("Africa/Juba"));
}
Any method level @DefaultTimeZone
configurations will override class level configurations:
@DefaultTimeZone("CET")
class MyTimeZoneTests {
@Test
void test_with_class_level_configuration() {
assertThat(TimeZone.getDefault()).isEqualTo(TimeZone.getTimeZone("CET"));
}
@Test
@DefaultTimeZone("Africa/Juba")
void test_with_method_level_configuration() {
assertThat(TimeZone.getDefault()).isEqualTo(TimeZone.getTimeZone("Africa/Juba"));
}
}
Note
|
A class-level configuration means that the specified time zone is set before and reset after each individual test in the annotated class. |
Thread-Safety
Since default locale and time zone are global state, reading and writing them during parallel test execution can lead to unpredictable results and flaky tests.
The @DefaultLocale
and @DefaultTimeZone
extensions are prepared for that and tests annotated with them will never execute in parallel (thanks to resource locks) to guarantee correct test results.
However, this does not cover all possible cases. Tested code that reads or writes default locale and time zone independently of the extensions can still run in parallel to them and may thus behave erratically when, for example, it unexpectedly reads a locale set by the extension in another thread. Tests that cover code that reads or writes the default locale or time zone need to be annotated with the respective annotation:
-
@ReadsDefaultLocale
-
@ReadsDefaultTimeZone
-
@WritesDefaultLocale
-
@WritesDefaultTimeZone
Tests annotated in this way will never execute in parallel with tests annotated with @DefaultLocale
or @DefaultTimeZone
.