Monday, December 17, 2012

Addressing the challenges of TDD in SharePoint – Attribute based registration of types to Service Locator


Dependency injection bindings through an IOC container can be achieved by different ways. For e.g. you can use an XML file based configuration for registering types or use an imperative code block for registration. Both of these methods use an explicit way if registering and resolving types.
Another common and an easy approach is to use attributes to register and resolve types. In this post, we'll extend the SharePoint service locator, to register types based on attributes to the container, which can be later used to resolve the mappings.

Creating the attribute:
public class SetAutoRegistration : Attribute, ISpAttribute
{   
    public Type InterfaceType { get; private set; }

    public string Key { get; private set; }

    public SetAutoRegistration(Type interfaceType) : this(interfaceType, string.Empty)
    {
    }

    public SetAutoRegistration(Type interfaceType, string key)
    {
        InterfaceType = interfaceType;
        Key = key;
    }
}

Creating a mappings object to define type mappings:
public class Mapping
{
    public Type FType { get; private set; }
   
    public Type TType { get; private set; }
   
    public string Key { get; private set; }

    public Mapping(Type fType, Type tType, string key)
    {
        FType = fType;
        TType = tType;
        Key = key;
    }
}

Extending the ServiceLocator class to add type based mappings:
[SharePointPermission(SecurityAction.InheritanceDemand, ObjectModel = true)]
[SharePointPermission(SecurityAction.LinkDemand, ObjectModel = true)]
public void RegisterTypeMapping(Type fromType, Type toType)
{
    RegisterTypeMapping(fromType, toType, null);
}

[SharePointPermission(SecurityAction.InheritanceDemand, ObjectModel = true)]
[SharePointPermission(SecurityAction.LinkDemand, ObjectModel = true)]
public void RegisterTypeMapping(Type fromType, Type toType, string key)
{
    var typeMappings = GetConfigData();
    var newTypeMapping = new TypeMapping(fromType, toType, null) { InstantiationType = InstantiationType.NewInstanceForEachRequest };
    RemovePreviousMappingsForFromType(typeMappings, newTypeMapping);
    typeMappings.Add(newTypeMapping);
    SetTypeMappingsList(typeMappings);
}

[SharePointPermission(SecurityAction.InheritanceDemand, ObjectModel = true)]
[SharePointPermission(SecurityAction.LinkDemand, ObjectModel = true)]
public void RemoveTypeMappings(Type type)
{
    var typeMappings = GetConfigData();
    foreach (var mapping in typeMappings.ToArray())
    {
        if (mapping.FromType == type.AssemblyQualifiedName)
        {
            typeMappings.Remove(mapping);
        }
    }

    SetTypeMappingsList(typeMappings);
}

Using reflection to register types to service locator during feature activating:
var assembly = Assembly.Load(assemblyToProbe);
var typesToAdd =
    assembly.GetTypes().Where(x => x.GetCustomAttributes(typeof (SetAutoRegistration), false).Length > 0);
types.AddRange(typesToAdd);
var mappings = BuildMappingsFromTypes(types);
foreach (var mapping in mappings)
{
    if (mapping.Key == string.Empty)
        serviceLocatorConfig.RegisterTypeMapping(mapping.FType, mapping.TType);
    else
        serviceLocatorConfig.RegisterTypeMapping(mapping.FType, mapping.TType, mapping.Key);
}

Attribute based registration in action:
[SetAutoRegistration(typeof(IMyRepository))]
public class MyRepository : BaseRepository<MyEntity>, IMyRepository
{
You can use the same approach to register types to activating service locator for the test cases.

Sunday, December 16, 2012

Addressing the challenges of TDD in Sharepoint – Decoupling the consumer and implementation


The SharePoint Service Locator is a reusable component from the MS Patterns & Practices that provides a simple implementation of the service locator pattern. You can use it in your own SharePoint applications to decouple the consumers of an interface from the implementations of that interface. Instead of creating an object by invoking the constructor of a class, you request an object with a specified interface from the service locator. The service implementation can now be replaced or updated without altering the consuming class implementation.
The usage of service locator makes it easy to dependencies that are scattered throughout various projects and solutions. These dependencies often make it challenging to maintain code over time—if you modify one class, you must recompile every project that references that class. This also makes unit testing code in isolation much more complicated. In short, decoupling your code from specific types makes your code more modular, easier to manage, and easier to test.
You can use the RegsiterTypeMapping method of the ServiceLocatorConfig instance to register the mappings to the service locator.
var serviceLocator = SharePointServiceLocator.GetCurrent();
var mappingsConfig = serviceLocator.GetInstance<IServiceLocatorConfig>();
mappingsConfig.RegisterTypeMapping<IMyService, MyService>();
You can retrieve the interface implementation later in your code using the GetInstance method of the ServiceLocatorConfig instance.
serviceLocator.GetInstance<IMyService>();
Normally you register the instances during the feature activating event and you need to remove the registered mappings from the service locator during feature deactivating event using the remove mappings method.
var serviceLocator = SharePointServiceLocator.GetCurrent();
var mappingsConfig = serviceLocator.GetInstance<IServiceLocatorConfig>();
mappingsConfig.RemoveTypeMapping<IMyService>(null);

Unit testing challenge – Replacing the ServiceLocator in the test context
The service locator from the P&P uses the sharepoint object model to keep store of the mappings and other properties. To successfully unit test the code that uses the service locator, you need to either use a wrapper object for the service locator or use the ActivatingServiceLocator object instead of the ServiceLocator in the test code.
To replace the service locator instance, you need to replace the actual service locator with the ActivatingServiceLocator instance as given below.
var activatingServiceLocator = new ActivatingServiceLocator();
SharePointServiceLocator.ReplaceCurrentServiceLocator(activatingServiceLocator);
const string type1 = "Type1";
const string type2 = "Type2";

activatingServiceLocator.RegisterTypeMapping<INotRegisteredType, NotRegisteredType1>(type1);
activatingServiceLocator.RegisterTypeMapping<INotRegisteredType, NotRegisteredType1>(type2);

var notRegisteredType = SpServiceLocator.GetInstance<INotRegisteredType>(type1);
Assert.IsInstanceOfType(notRegisteredType, typeof(NotRegisteredType1));
SharePointServiceLocator.Reset();

Sunday, December 9, 2012

Painless unit testing - sharepoint emulators


With the availability of Visual Studio 2012 SharePoint Emulators the isolation of the SharePoint API is much easier compared to the old way of isolating using the Moles or Fakes framework.
In order to incorporate emulators into existing tests you should wrap the relevant code in a SharePointEmulationScope, which accepts EmulationMode enum as a parameter. It is enabled by default which in turn performs run time interception of all Microsoft.SharePoint.dll calls.

You can use the new emulator in your unit test project by using nuget packaging manager and convert your old test case to the new emulation scope as given below

 [TestMethod]
public void BuildFromSPListItemShouldCreateANewObjectWithPopulatedValues()
{
    using(ShimsContext.Create())
    {
        var dataMapper = new MyObjectDataMapper();
        const string customDescription = "Custom Description";
        var spListItem = new ShimSPListItem
        {
            ItemGetString = (fieldName) =>
            {
                if (fieldName == BaseInternalFields.Id) return 1;
                if (fieldName == BaseInternalFields.Title)
                    return "Some Title";
                return fieldName == RulesInternalFields.CustomDesc
                    ? customDescription
                            : null;
            },
            FieldsGet = () => new ShimSPFieldCollection
            {
                ContainsFieldString =
                    (internalName) =>
                    internalName.Equals(BaseInternalFields.Id) ||
                    internalName.Equals(BaseInternalFields.Title) ||
                    internalName.Equals(RulesInternalFields.CustomDesc)
            }
        };

        var myObject = dataMapper.FromSPListItem(spListItem);
        Assert.IsTrue(myObject.CustomDesc == customDescription);
    }
}


[TestMethod]
public void BuildFromSPListItemShouldCreateANewObjectWithPopulatedValues ()
{
    using (var emulation = new SharePointEmulationScope(EmulationMode.Enabled))
    {
        var dataMapper = new MyObjectDataMapper();
        const string customDescription = "Custom Description";
        using(var emulatedSite = new SPSite("http://localhost:8081/MySite"))
        {
            var listId = emulatedSite.RootWeb.Lists.Add("MyList", "Custom list", SPListTemplateType.GenericList);
            var list = emulatedSite.RootWeb.Lists[listId];
            var listitem = list.Items.Add();
            listitem["Title"] = "mytitle";
            listitem["CustomDesc"] = "Custom Description";

            var myObject = dataMapper.FromSPListItem(listitem);
            Assert.IsTrue(myObject.CustomDesc == customDescription);
        }
    }
}

Because the emulator relies on the Fakes framework, you can easily reuse your existing code to use the emulators without much pain.