As per title, I'm working on a codebase that supports localization for several cultures. I rely on setting culture as follows in middleware early in the request pipeline:
string lang = "fr-FR";
Thread.CurrentThread.CurrentCulture = new CultureInfo(lang);
Thread.CurrentThread.CurrentUICulture = new CultureInfo(lang);
I deployed it manually on a test server and tested it manually and it seems to work. However, I want to write some unit tests/end-to-end tests (whatever makes more sense), to validate this.
First off, I'm facing some problems in changing CurrentThread.CurrentCulture in the unit test environment. Moreover I'm unsure if mocking does really make a database makes sense as or really does test the localization.
Sample Test approach that I'm currently considering:
public class LocalizationTest
{
private readonly Mock<IMenuService> _menuService;
private readonly Mock<IDiscountService> _discountService;
private readonly Mock<IConfiguration> _configuration;
public LocalizationTest()
{
_menuService = new Mock<IMenuService>();
_discountService = new Mock<IDiscountService>();
_configuration = new Mock<IConfiguration>();
}
[Fact]
public async Task Should_Return_Valid_Menu()
{
//Arrange
_menuService.Setup(x => x.GetItemAsync(It.IsAny<int>(), It.IsAny<int[]>()
, It.IsAny<string>(), It.IsAny<bool>()))
.ReturnsAsync(() => LocalizedMenuItemChoice(Thread.CurrentThread.CurrentUICulture));
_configuration.SetupGet(x => x[It.IsAny<string>()]).Returns("Mocked Value");
ConfigurationHelper.Initialize(_configuration.Object);
var menuLogic = new MenuLogic(_menuService.Object);
var requestModel = new GetMenuItemChoicesRequestModel()
{
someData = 1,
someDataId = 2,
someDataList = new int[1] { 3 },
someDataNum = 4,
};
string lang = "fr-France"
Thread.CurrentThread.CurrentCulture = new CultureInfo(lang);
Thread.CurrentThread.CurrentUICulture = new CultureInfo(lang);
//Act
var response = await menuLogic.GetItemsChoicesAsyncV2(requestModel);
//Assert
Assert.Equal(JsonConvert.SerializeObject(LocalizedMenuItemChoice(Thread.CurrentThread.CurrentCulture)) , JsonConvert.SerializeObject(response));
}
private ItemsList LocalizedMenuItemChoice(CultureInfo cultureInfo)
{
// Example: Switching between English and French data
if (cultureInfo.Name == "fr-FR")
{
return new ItemList() {
//fr-FR DATA
};
}
else
{
return new ItemList() {
//en-US DATA
};
}
}
}
I would probably not write automated tests that use the actual responses from a webpage, since that would likely break the test even for valid and intended changes. And automated tests are much less valuable if you need to spend as much time updating old tests as you do implementing features.
In my experience the most common problems with translations are:
You can write automated tests for the first three points fairly easily. But you do not need to actually change the language, just iterate over all the strings in the translation files. But you might need a list of exceptions to handle point 3, since some strings are identical in multiple languages.
Point 4 is not very effective to unit test in my experience, since it is mostly caused by just forgetting to move a literal, and you will most likely not remember to write a unit test if that is the case. I have seen various approaches to minimize this risk:
Note that you will need to do some manual testing of each translation anyway. If for no other reason than to check that the UI does not look weird due to string or word length, (looking at you Finland!)
For the final point you just need someone you trust that knows the language and the domain. If an external translator makes a bad translation you have little chance to catch the error if you have no one that understands the language.