sshushliapin / Sitecore.FakeDb

Unit testing framework for Sitecore.
MIT License
117 stars 36 forks source link

GetLanguageItemId doesn't work with FakeDb #179

Closed Quatra closed 7 years ago

Quatra commented 7 years ago

Hello,

I am trying to test my code that is working with Language Fallback. In my code, i am doing this instruction : Sitecore.Data.Managers.LanguageManager.GetLanguageItemId(Sitecore.Context.Language, Sitecore.Context.Database)

Unfortunatly, I am not able to retrieve the Language Item Id from the Fake Db.

I've created the language item and i've set it to the Sitecore.Context.Language but it doesn't retrieve the item.

var langItem = new DbItem("en-US", new ID(), templateId);
            langItem.Fields.Add(charsetId, "iso-8859-1");
            langItem.Fields.Add(codePage, "65001");
            langItem.Fields.Add(dictionary, "");
            langItem.Fields.Add(encoding, "utf-8");
            langItem.Fields.Add(fallbackLanguage, "");
            langItem.Fields.Add(iso, "en");
            langItem.Fields.Add(regionalIsoCode, "en-US");

            db.Add(langItem);

            var defaultLanguage = db.GetItem(langItem.ID)
db = db.WithLanguages(Language.Parse("en"), Language.Parse("en-US"), Language.Parse("en-CA"));
            Sitecore.Context.Language = Language.Parse("en-US");
            Sitecore.Context.Language.Origin.ItemId = defaultLanguage.ID;

I've noticed that the code in the LanguageManager is looking for the property ItemId of the object Origin but i wasn't able to clearly understand how it is set. I am assuming that there is something missing in the SwitchingLanguageDataProvider but i am not sure.

EDIT: I just wanted to tell that I am using Sitecore 8.2 update 1 and FakeDb 1.6.0

Regards

sshushliapin commented 7 years ago

FakeDb does not use the Default Sitecore language provider that reads languages from items. The main reason is that the provider is also responsible for cashing which may lead to unexpected surprises in unit tests.

I've noticed that the code in the LanguageManager is looking for the property ItemId of the object Origin but i wasn't able to clearly understand how it is set.

Good catch, thanks for pointing me into this direction. The Origin.ItemId can be easily set via the open setter property:

public class LanguageManagerTest
{
    [Fact]
    public void GetLanguageItemSample()
    {
        var languageItemId = ID.NewID;
        var language = Language.Parse("en-CA");
        language.Origin.ItemId = languageItemId;
        var languageItem = new DbItem("en-CA", languageItemId, ID.NewID);

        using (var db = new Db()
            .WithItems(languageItem)
            .WithLanguages(language))
        {
            var actualLangItemId = LanguageManager.GetLanguageItemId(language, db.Database);
            Assert.Equal(languageItemId, actualLangItemId);

            var actualLangItem = LanguageManager.GetLanguageItem(language, db.Database);
            Assert.NotNull(actualLangItem);
        }
    }
}

public static class DbExtensions
{
    public static Db WithItems(this Db db, params DbItem[] items)
    {
        foreach (var item in items)
        {
            db.Add(item);
        }

        return db;
    }
}

Please note that you do not need to set all the real language item fields (of course, unless they're really required for your test).

Please also note that trying to write as simple sample as possible, I introduced new db.WithItems extension. That is not part of FakeDb so far, but it looks good to me so maybe it make sense to include it into a next release.

Quatra commented 7 years ago

Hello Sergey Shushlyapin,

Thank you for this piece of code. With this, I was able to mock the method and continue on my testing. For testing purpose and to help others, here is what i've created.

private Dictionary<string, Item> CreateLanguages(Db db)
{
    ID templateId = new ID("{F68F13A6-3395-426A-B9A1-FA2DC60D94EB}");
    ID charsetId = new ID("{49E5E8F3-ED4A-4A06-ABE1-B9408951DEE9}");
    ID codePage = new ID("{990596CE-0024-43F3-BF4C-A991BFA69B45}");
    ID dictionary = new ID("{60669E54-7B9C-4B55-A0C4-8F25059D8B94}");
    ID encoding = new ID("{8728D8FF-66D9-40C2-8B34-C4FC1466942E}");
    ID fallbackLanguage = new ID("{892975AC-496F-4AC9-8826-087095C68E1D}");
    ID iso = new ID("{C437E416-8948-427D-A982-8ED37AE3F553}");
    ID regionalIsoCode = new ID("{0620F810-9294-4F14-AF9F-F5772EFCA0B2}");

    var items = new Dictionary<string, Item>();
    var langName = "en-US";
    var langItem = new DbItem(langName, new ID(), templateId);
    langItem = new DbItem(langName, new ID(), templateId);
    langItem.Fields.Add(charsetId, "iso-8859-1");
    langItem.Fields.Add(codePage, "65001");
    langItem.Fields.Add(dictionary, "en-US.tdf");
    langItem.Fields.Add(encoding, "utf-8");
    langItem.Fields.Add(fallbackLanguage, "en");
    langItem.Fields.Add(iso, "en");
    langItem.Fields.Add(regionalIsoCode, "en-US");

    var language = Language.Parse(langName);
    language.Origin.ItemId = langItem.ID;
    db.Add(langItem);
    var allLanguagesList = new List<Language>();
    allLanguagesList.Add(language);
    items.Add(langName, db.GetItem(langItem.ID));

    langName = "en-CA";
    langItem = new DbItem(langName, new ID(), templateId);
    langItem.Fields.Add(charsetId, "iso-8859-1");
    langItem.Fields.Add(codePage, "65001");
    langItem.Fields.Add(dictionary, "");
    langItem.Fields.Add(encoding, "utf-8");
    langItem.Fields.Add(fallbackLanguage, "en");
    langItem.Fields.Add(iso, "en");
    langItem.Fields.Add(regionalIsoCode, "en-CA");

    language = Language.Parse(langName);
    language.Origin.ItemId = langItem.ID;
    allLanguagesList.Add(language);
    db.Add(langItem);
    items.Add(langName, db.GetItem(langItem.ID));

    langName = "en";
    langItem = new DbItem(langName, new ID("{AF584191-45C9-4201-8740-5409F4CF8BDD}"), templateId);
    langItem.Fields.Add(charsetId, "");
    langItem.Fields.Add(codePage, "");
    langItem.Fields.Add(dictionary, "en-US.tdf");
    langItem.Fields.Add(encoding, "");
    langItem.Fields.Add(fallbackLanguage, langName); // This is wierd that by default it fallback to itself.
    langItem.Fields.Add(iso, "en");
    langItem.Fields.Add(regionalIsoCode, "");

    language = Language.Parse(langName);
    language.Origin.ItemId = langItem.ID;
    allLanguagesList.Add(language);
    db.Add(langItem);
    items.Add(langName, db.GetItem(langItem.ID));

    db.WithLanguages(allLanguagesList.ToArray());

    return items;
}

With this code, I am able to test the fallback because the fallback field is set.

Regards,