Skip to content

Instantly share code, notes, and snippets.

@digulla
Last active March 9, 2022 17:16
Show Gist options
  • Save digulla/5884162 to your computer and use it in GitHub Desktop.
Save digulla/5884162 to your computer and use it in GitHub Desktop.
JUnit 4 Rule to run individual tests with a different default locale
import java.util.Locale;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
public class DefaultLocaleRule extends TestWatcher {
private Locale originalDefault;
private Locale currentDefault;
public DefaultLocaleRule() {
this( null );
}
public DefaultLocaleRule( Locale defaultForTests ) {
currentDefault = defaultForTests;
}
@Override
protected void starting( Description description ) {
originalDefault = Locale.getDefault();
if( null != currentDefault ) {
Locale.setDefault( currentDefault );
}
}
@Override
protected void finished( Description description ) {
Locale.setDefault( originalDefault );
}
public void setDefault( Locale locale ) {
if( null == locale ) {
locale = originalDefault;
}
Locale.setDefault( locale );
}
public static DefaultLocaleRule en() {
return new DefaultLocaleRule( Locale.ENGLISH );
}
public static DefaultLocaleRule de() {
return new DefaultLocaleRule( Locale.GERMAN );
}
public static DefaultLocaleRule fr() {
return new DefaultLocaleRule( Locale.FRENCH );
}
}
To use the rule, add this to your JUnit test class:
// make all tests run with the English locale
@Rule
public DefaultLocaleRule defaultLocaleRule = DefaultLocaleRule.en();
If a test has special demands, you can switch:
@Test
public void testDE() {
defaultLocaleRule.setDefault( Locale.GERMAN );
...
}
@belgoros
Copy link

It fails when using before_classand javax.validation.Validator as follows:

public class EntrepriseNotEmptyValidatorTest {

    private static Validator validator;
    @Rule
    public DefaultLocaleRule defaultLocaleRule = DefaultLocaleRule.en();

    @BeforeClass
    public static void setUp() {
        /*Locale locale = new Locale("fr", "FR");
        Locale.setDefault(locale);*/
        System.out.println("Locale default: " + Locale.getDefault());
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();

    }

    @Test
    public void siretShouldNotBeNull_FR() {
        //defaultLocaleRule.setDefault(Locale.FRENCH);
        System.out.println("Locale default in test: " + Locale.getDefault());
        EntrepriseDTO entrepriseDTO = new EntrepriseDTO();
        entrepriseDTO.setRaisonSociale("example");
        Set<ConstraintViolation<EntrepriseDTO>> constraintViolations = validator.validate(entrepriseDTO);
        assertEquals(1, constraintViolations.size());
        assertEquals("Le champ siret doit être renseigné", constraintViolations.iterator().next().getMessage());
    }

    @Test
    public void raisonSocialeShouldNotBeNull_FR() {
        //defaultLocaleRule.setDefault(Locale.FRENCH);
        System.out.println("Locale default in test: " + Locale.getDefault());
        EntrepriseDTO entrepriseDTO = new EntrepriseDTO();
        entrepriseDTO.setSiret("azerty");
        Set<ConstraintViolation<EntrepriseDTO>> constraintViolations = validator.validate(entrepriseDTO);
        assertEquals(1, constraintViolations.size());
        assertEquals("Le champ raison sociale doit être renseigné", constraintViolations.iterator().next().getMessage());
    }
}

Here is the output:

Locale default in test: fr

org.junit.ComparisonFailure: 
Expected :Le champ siret doit être renseigné
Actual   :Field siret should not be empty
   <Click to see difference>


    at org.junit.Assert.assertEquals(Assert.java:125)
    at org.junit.Assert.assertEquals(Assert.java:147)
    at fr.franceagrimer.expadon2.dto.validator.EntrepriseNotEmptyValidatorTest.siretShouldNotBeNull_FR(EntrepriseNotEmptyValidatorTest.java:44)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:47)
    at org.junit.rules.RunRules.evaluate(RunRules.java:18)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

Locale default in test: fr

org.junit.ComparisonFailure: 
Expected :Le champ raison sociale doit être renseigné
Actual   :Field raison sociale should not be empty
   <Click to see difference>


    at org.junit.Assert.assertEquals(Assert.java:125)
    at org.junit.Assert.assertEquals(Assert.java:147)
    at fr.franceagrimer.expadon2.dto.validator.EntrepriseNotEmptyValidatorTest.raisonSocialeShouldNotBeNull_FR(EntrepriseNotEmptyValidatorTest.java:55)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:47)
    at org.junit.rules.RunRules.evaluate(RunRules.java:18)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

Locale default: en_US
log4j:WARN No appenders could be found for logger (org.jboss.logging).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

Process finished with exit code 255

It seems like Validator does not take it in account.
By te way, if I remove the commented code that forces th FR locale in before_classblock, and remove all the call to DefaultRule class, it works as need. Unfortunately, it is not so DRY and the FR locale has to beard coded :(.
Any idea about that?
Thank you.

@belgoros
Copy link

I found the reason. It seems like @BeforeClass block are run first, then @rule block is run. So the solute I found is to replace the @rule annotation with @ClassRule that is run before @BeforeClass block and the rule variable should be static:

@ClassRule
    public static DefaultLocaleRule defaultLocaleRule = DefaultLocaleRule.fr();

    @BeforeClass
    public static void setUp() {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment