After creating my Localization provider, I wanted to create some unit test for it. I took Joel Abrahamsson’s Tests for the EPiServer 7 MVC templates as a starting point.
As this is a localization provider, which uses e.g. strongly typed lookups I needed to add more “Fakes” to the CmsContext, e.g. the ContentTypeRepository and the LocalizationService. I also needed to add more “Fake lookups”. Just look in the code which ones I needed.
To be able to create my ContentTypes I added a helper method.
public void CreatePageType(Type pageType)
{
this.nextPageTypeId += 1;
ContentTypeAttribute attribute =
(ContentTypeAttribute)
Attribute.GetCustomAttribute(pageType, typeof(ContentTypeAttribute));
ContentType contentType = A.Fake();
contentType.ID = this.nextPageTypeId;
contentType.ModelType = pageType;
contentType.Name = pageType.Name;
contentType.GUID = attribute.GetGUID().GetValueOrDefault();
contentType.Description = attribute.Description;
contentType.DisplayName = attribute.DisplayName;
contentType.IsAvailable = attribute.AvailableInEditMode;
contentType.GroupName = "UnitTests";
contentType.SortOrder = 100;
contentType.ACL = new AccessControlList();
this.pageTypes.Add(contentType);
A.CallTo(() => this.ContentTypeRepository.Load(pageType.Name))
.Returns(this.pageTypes.FirstOrDefault(pt => pt.Name.Equals(pageType.Name)));
A.CallTo(() => this.ContentTypeRepository.Load(pageType)).Returns(this.pageTypes.FirstOrDefault(pt => pt.Name.Equals(pageType.Name)));
}
So, now I can add my ContentTypes. Next create the fake pages, in this case the translation containers. To be able to do this I created two helper methods that create a basic page and one to create a language version for it.
[NotNull]
public T CreateContent([NotNull] string name, [NotNull] ContentReference parentLink) where T : PageData, new()
{
// Get the ContentType for the page you want to create
ContentType contentType = this.ContentTypeRepository.Load(typeof(T));
T page = new T();
page.Property["PageWorkStatus"] = new PropertyNumber((int)VersionStatus.Published);
page.Property["PageStartPublish"] = new PropertyDate(DateTime.Now.AddDays(-1));
page.Property["PageName"] = new PropertyString(name);
page.Property["MasterLanguageBranch"] = new PropertyString(CultureInfo.CurrentUICulture.Name);
page.Property["PageLanguageBranch"] = new PropertyString(CultureInfo.CurrentUICulture.Name);
page.Language = new CultureInfo(CultureInfo.CurrentUICulture.Name);
page.Property["PageParentLink"] = new PropertyPageReference(parentLink);
page.Property["PageLink"] = new PropertyPageReference();
page.ContentLink = parentLink == ContentReference.RootPage
? ContentReference.StartPage
: new PageReference(++this.nextPageId);
page.ExistingLanguages = new List { new CultureInfo(CultureInfo.CurrentUICulture.Name) };
// If no ContentType can be found, just create the ContentData without a ContentType
if (contentType.ID > 0)
{
page.Property["PageTypeID"] = new PropertyNumber(contentType.ID);
page.Property["PageTypeName"] = new PropertyString(contentType.Name);
page.Property["ContentTypeID"] = new PropertyNumber(contentType.ID);
}
this.AddChild(page.ParentLink, page);
return page;
}
[NotNull]
public T CreateLanguageVersionOfContent([NotNull] ContentReference contentLink, [NotNull] LanguageSelector languageSelector) where T : PageData, new()
{
// Get the original page
T page =
this.ContentRepository.Get(
contentLink, new LanguageSelector(CultureInfo.CurrentUICulture.Name)) as T;
if (page == null)
{
throw new ContentNotFoundException();
}
// Create a copy
T languageVersion = page.CreateWritableClone() as T;
if (languageVersion == null)
{
throw new EPiServerException("Creating a copy of the item did not succeed.");
}
// Set the language to the new version
languageVersion.Language = new CultureInfo(languageSelector.LanguageBranch);
// Set the contentlink to self, as it is a language version
languageVersion.ContentLink = contentLink;
// Add new language to the version
languageVersion.ExistingLanguages = new List
{
new CultureInfo(page.LanguageBranch),
new CultureInfo(
languageSelector.LanguageBranch)
};
// Add new language to the original
page.ExistingLanguages = new List
{
new CultureInfo(page.LanguageBranch),
new CultureInfo(languageSelector.LanguageBranch)
};
this.AddChild(page.ParentLink, languageVersion);
return languageVersion;
}
As this just takes care of the basic properties, whenever you need more properties you can use these methods to create the base and set the remaining properties later.
[NotNull]
protected static TranslationItem CreateTranslationItem([NotNull] string originalText, [NotNull] string translation, [NotNull] ContentReference parentLink, [NotNull] LanguageSelector languageSelector)
{
// Create the base item
TranslationItem translationItem = CmsContext.CreateContent(
originalText, parentLink);
// Set the additional properties for this type.
translationItem.OriginalText = originalText;
translationItem.Translation = translation;
return translationItem;
}
[NotNull]
protected static TranslationItem AddLanguageVersionToTranslationItem([NotNull] ContentReference contentLink, [NotNull] string translation, [NotNull] LanguageSelector languageSelector)
{
// Create the base language version
TranslationItem translationItem = CmsContext.CreateLanguageVersionOfContent(
contentLink, languageSelector);
// Change the properties that need changing for this version.
translationItem.Translation = translation;
return translationItem;
}
This is the plumbing, now on with the actual test. In the specs for the translation tests, I create my ContentTypes, containers, language items and instantiate my localization provider.
[UsedImplicitly]
private Establish context = () =>
{
CmsContext = new CmsContext();
CmsContext.CreatePageType(typeof(TranslationContainer));
CmsContext.CreatePageType(typeof(TranslationItem));
CmsContext.CreatePageType(typeof(CategoryTranslationContainer));
LanguageSelector masterLanguageSelector = new LanguageSelector(CmsContext.MasterLanguage.Name);
LanguageSelector secondLanguageSelector = new LanguageSelector(CmsContext.SecondLanguage.Name);
CmsContext.CreateContent("StartPage", ContentReference.RootPage);
ContentReference containerReference = CmsContext.CreateContent("Translations", ContentReference.StartPage).ContentLink;
CmsContext.CreateLanguageVersionOfContent(containerReference, secondLanguageSelector);
ContentReference itemReference = CreateTranslationItem("TextOne", "Translation One", containerReference, masterLanguageSelector).ContentLink;
AddLanguageVersionToTranslationItem(itemReference, "Vertaling Een", secondLanguageSelector);
ContentReference subContainerReference = CmsContext.CreateContent("SubTranslations", containerReference).ContentLink;
CreateTranslationItem("SubTextOne", "SubTranslation One", subContainerReference, masterLanguageSelector);
ContentReference categoryContainerReference = CmsContext.CreateContent("Categories", containerReference).ContentLink;
CmsContext.CreateLanguageVersionOfContent(categoryContainerReference, secondLanguageSelector);
ContentReference categoryReference = CreateTranslationItem("CategoryOne", "CategoryTranslation One", categoryContainerReference, masterLanguageSelector).ContentLink;
AddLanguageVersionToTranslationItem(categoryReference, "CategorieVertaling Een", secondLanguageSelector);
NameValueCollection configValues = new NameValueCollection { { "containerid", "0" } };
LocalizationProvider = new TranslationProvider();
// Instanciate the provider
LocalizationProvider.Initialize("Translations", configValues);
// Add it at the end of the list of providers.
CmsContext.ProviderBasedLocalizationService.Providers.Add(LocalizationProvider);
};
Last I added some test scenarios, e.g. using the translate control
[Subject("Translations")]
public class Get_a_translation_for_a_translate_control : TranslationSpecs
{
/// The result.
///
private static string result;
/// The control
///
private static Translate translate = new Translate { Text = "/textone" };
/// Should be the translated control.
///
private Because of = () => result = CmsContext.GetRenderedText(translate);
/// Should be the translated control.
///
private It should_be_the_translated_value = () => result.ShouldEqual("Translation One");
}
It took some time figuring out what needed to be faked, e.g. a translation for a category uses a TryGetExistingInstance to get the provider. So that needed to be faked to.
A.CallTo(() => ServiceLocator.Current.TryGetExistingInstance(out ignored)).Returns(true).AssignsOutAndRefParameters(this.ProviderBasedLocalizationService);
I tried to make my plumbing as generic as possible so I can use it to test more providers, and whatever I may come up with next.
The code can be found on GitHub, together with the provider.