2

I am receiving the following error using Glass Mapper

System.Collections.Generic.KeyNotFoundException : The given key was not present in the dictionary.
   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   at Glass.Mapper.AbstractService..ctor(String contextName)
   at Glass.Mapper.Sc.SitecoreService..ctor(Database database, String contextName)
   at Glass.Mapper.Sc.ItemExtensions.GlassCast[T](Item item, Boolean isLazy, Boolean inferType)

Here are the details of my configuration. I'm using a unit test project that has the same Glass Mapper version installed as the project it tests. My GlassMapperScCustom.cs in the Unit Test Project is below:

    public static class GlassMapperScCustom
    {
        public static void CastleConfig(IWindsorContainer container)
        {
            var config = new Config();

            container.Install(new SitecoreInstaller(config));
        }

        public static IConfigurationLoader[] GlassLoaders()
        {
            return new IConfigurationLoader[] { };
        }
        public static void PostLoad()
        {

        }
    }

Additionally, I have GlassMapper.Sc.Mvc.config in the App_Config folder and that is the only one.

The exception above occurs when the Code Under Test (CUT) calls the following line:

var paths = pathFolder.GetChildren().Select(child => child.GlassCast<Path>());

Based on what I've searched online, I need to be able to set the SitecoreContext in order for GlassMapper to work correctly. How and where would I do that; in the unit test project or the CUT project? Or is this some other issue entirely?

Edit:

Here are the Glass Mapper versions:

<package id="Glass.Mapper" version="3.0.13.25" targetFramework="net461" />
<package id="Glass.Mapper.Sc" version="3.2.2.45" targetFramework="net461" />
<package id="Glass.Mapper.Sc.CastleWindsor" version="3.2.1.23" targetFramework="net461" />
<package id="Glass.Mapper.Sc.Mvc-5" version="3.2.1.42" targetFramework="net461" />
  • what version of glass mapper do you have? – Vlad Iobagiu Nov 27 '16 at 10:26
  • I updated the question to include the versions from my package config in the unit test project. – uioporqwerty Nov 27 '16 at 10:52
  • Can you check if you deploy Website\App_Config\Include\Glass.Mapper.Sc.CastleWindsor.config file – Vlad Iobagiu Nov 27 '16 at 12:34
  • @uioporqwerty Has something from my answer failed to work for you? – Dmytro Shevchenko Nov 28 '16 at 17:21
  • Sorry, it's a very well written answer but it hasn't resolved my issue yet. Based on the Glass Mapper version we're using, we don't have the .Cast<T> method for sitecorecontext. I've tried using var context = new SitecoreContext(Context.Database); var paths = pathFolder.GetChildren().Select(child => context.CreateType<=Path>(child)); which is the recommended way of glass mapping for this version of glass mapper. But the same error occurs on the first line which leads me to believe there is a problem with SitecoreFakeDb and not Glass Mapper itself. – uioporqwerty Nov 28 '16 at 17:52
4

Unit testing

Your question says that your tests are unit tests, so first I'll talk about a proper unit testing approach. Such tests should be run in isolation, meaning that your module shouldn't rely on data coming from a Sitecore database. You should provide mocks for all data consumed by code under test.

To make this possible, you'll need to ensure that the module does not rely on static context. Instead, it should employ Dependency Injection to obtain dependencies.

In this case, the module should be injected with Glass.Mapper.Sc.ISitecoreContext and use it for all Glass operations. Here's an example:

public class SomeModule
{
    private readonly ISitecoreContext _sitecoreContext;

    public SomeModule(ISitecoreContext context)
    {
        this._sitecoreContext = context;
    }

    public void SomeMethod()
    {
        // ...
        IEnumerable<Item> pathItems = ...;
        var paths = pathItems.Select(child => this._sitecoreContext.Cast<Path>(child));
        // ...
    }
}

Then in the Unit test code you will instantiate the module with a mock implementation of ISitecoreContext passed into its constructor. You can either create your own mock implementation (it's pretty easy), or you can use mocking frameworks, such as NSubstitute, Moq, FakeItEasy or Rhino Mocks.

Integration testing

Tests that actually get data from an external storage are not considered unit tests, they are called integration tests.

To make tests run outside of a Sitecore page context, you will need to manually create some dependencies, such as the Glass ISitecoreContext, and pass them into the module being tested. This means you should still apply exactly the same approach (as if you were unit testing) to the design of SomeModule—it should accept ISitecoreContext as a constructor argument and use it for accessing Sitecore data. The only difference will be that your test code will inject a real context instance into the module.

Here's how you can do it:

// Prepare the environment
if (Glass.Mapper.Context.Default == null)
{
    var config = new Glass.Mapper.Sc.Config();
    var dependencyResolver = new Glass.Mapper.Sc.IoC.DependencyResolver(config);
    Glass.Mapper.Context.Create(dependencyResolver, "Default", true);
}

// Create the Sitecore context
Database db = Factory.GetDatabase("master");
var sitecoreContext = new SitecoreContext(db);

// Instantiate the module and use it
var module = new SomeModule(sitecoreContext);
module.SomeMethod();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.