Mocking LocalizationService
There is a rule of thumb in EPiServer is any code written should be covered by tests, either unit tests or integration tests. While we’re not 100% test covered, but we are trying hard to. It’s a requirement to write tests whenever possible, and it’s generally accepted for the first comment of any review is “Can we write tests for this?”
While most of EPiServer API:s are fairly easy to mock and to test, LocalizationService is not the case. I fall in this trap today when trying to mock it by Moq. To this point, I realized that most of method in this class is not virtual, meaning it’s not mockable by Moq. Worse, it does not have a parameterless constructor, which eliminate the hope of using the virtual GetStringByCulture(string resourceKey, string fallback, CultureInfo culture) for mock.
I was disappointed. “No, we can’t have a untestable API:s like this. This is bad." Until I found that CMS core guys were cool enough to save the day!
Along with LocalizationService, we provide a class named MemoryLocalizationService, inherited from it. As it name suggested, instead of loading localized strings from disk, it works entirely in memory, which suits perfectly for unittest.
Then you can write a code like this:
MemoryLocalizationService _localizationService = new MemoryLocalizationService(); _localizationService.AddString(CultureInfo.CurrentUICulture, "<key>", "<value>");
And you now have a perfectly injectable LocalizationService instance for your unit test.
While I would prefer the normal approach as it's much more well-known, I appreciate CMS core team to make mocking LocalizationService possible. I don't know the reason, but they might introduce this cool hack to avoid introduce breaking changes to our code base.
Happy unit testing!
Comments