32

I have some code I want to test. I want to check if a String is properly composed out of various strings that I have in resources. The challenge here is to deal with multiple translations in my resources. I know that locale can be an issue when testing a desktop application and that it is recommended that you create locale-independent tests.

I've found that you can set the locale programatically, but it was not recommended (see Change language programmatically in Android). While this question is aimed at changing locale at runtime when running an app normally, I was wondering if there was a better solution to my problem.

Community
  • 1
  • 1
Xilconic
  • 3,785
  • 4
  • 26
  • 35
  • I'm also interested in this, hence the bounty. My specifics: I'm testing from within Eclipse, and I'd like to be able to change locale, including timezone, as smoothly as possible, within a suite. I'd like to see a worked example of how to do it in an answer. – Matt Gibson Feb 16 '14 at 12:29
  • @MattGibson I updated my answer with a working example. It changes locale for the both the date formatters and the application resources. – sergej shafarenka Feb 21 '14 at 14:43

2 Answers2

64

If it's just for testing, then you can change the locale programmatically without any issues. It will change the configuration of your app and you will be able to test your code with the new locale. It has the same effect as if a user has changed it. If you want to automate your tests, you can write a script that changes locale using adb shell as described here, and launch your tests afterwards.

Here is an example of testing translations of word "Cancel" for English, German and Spanish locales:

public class ResourcesTestCase extends AndroidTestCase {

    private void setLocale(String language, String country) {
        Locale locale = new Locale(language, country);
        // here we update locale for date formatters
        Locale.setDefault(locale);
        // here we update locale for app resources
        Resources res = getContext().getResources();
        Configuration config = res.getConfiguration();
        config.locale = locale;
        res.updateConfiguration(config, res.getDisplayMetrics());
    }

    public void testEnglishLocale() {
        setLocale("en", "EN");
        String cancelString = getContext().getString(R.string.cancel);
        assertEquals("Cancel", cancelString);
    }

    public void testGermanLocale() {
        setLocale("de", "DE");
        String cancelString = getContext().getString(R.string.cancel);
        assertEquals("Abbrechen", cancelString);
    }

    public void testSpanishLocale() {
        setLocale("es", "ES");
        String cancelString = getContext().getString(R.string.cancel);
        assertEquals("Cancelar", cancelString);
    }

}

Here are the execution results in Eclipse:

enter image description here

Android O update.

When running in Android O method Locale.setDefault(Category.DISPLAY, locale) shall be used (see behaviour changes for more detail).

wrozwad
  • 2,610
  • 1
  • 30
  • 38
sergej shafarenka
  • 20,071
  • 7
  • 67
  • 86
  • 3
    I don't extend my tests with AndroidTestCase, so I cannot get the context. I'm using `@RunWith(RobolectricGradleTestRunner.class)`. So it seems like I cannot use the same solution. Any advice? – P Kuijpers Apr 14 '17 at 08:58
  • 1
    @PKuijpers In Robolectric, you need to override the locale using qualifiers in your test Config. See http://robolectric.org/using-qualifiers/ for more information. – Dennis Jun 12 '19 at 19:48
  • 2
    Please, try to reset the Locale in the tear down method, to avoid running into issues. – moxi Jul 01 '21 at 21:19
2

The current accepted answer didn't help me. But @Dennis's comment helped to solve the Problem for me.

Use Robolectric and override the locale by specifying a resource qualifier.

Add for example @Config(qualifiers="de-port") for the German language.

@Test
@Config(qualifiers = "de-port")
fun testGetLocaleGerman(){  ...   }

Robolectrics Documentation

Samuel
  • 356
  • 2
  • 13