Print Page | Close Window

Silverlight Unit testing and cocktail 2 beta

Printed From: IdeaBlade
Category: Cocktail
Forum Name: Community Forum
Forum Discription: A professional application framework using Caliburn.Micro and DevForce
URL: http://www.ideablade.com/forum/forum_posts.asp?TID=3758
Printed Date: 02-May-2024 at 6:54pm


Topic: Silverlight Unit testing and cocktail 2 beta
Posted By: Walid
Subject: Silverlight Unit testing and cocktail 2 beta
Date Posted: 01-Nov-2012 at 1:53pm
Hi,

Before the migration to cocktail 2 betal I had a working silverlight unit testing project.  Since the migration it doesn't work anymore, it crash on when accessing the Composition.Provider property in the CreateEntityManager method.

Looking at the changes in cocktail it looks normal,  having no bootstrapper in this project Mef isn't configured. I tried to manually create the MefCompositionProvider but it's not possible because it's an internal class. I checked the source of Cocktail I noticed this is exactly what you are doing in the Test Project but ... Cocktail makes its internal visible to it.

I don't know if it's possible to setup a boostrapper in this application because I don't have a ViewModel to give to it, the Viewmodel is created by the unit testing classes with the following method : UnitTestSystem.CreateTestPage()

How can I setup my silverlight unit testing application in order to have Mef configured ?



Replies:
Posted By: mgood
Date Posted: 01-Nov-2012 at 6:02pm
In general, IoC shouldn't be used for unit testing. You should fake composition by implementing a fake ICompositionProvider. I'm debating now making MefCompositionProvider public for cases where testing with MEF may make sense.


Posted By: Walid
Date Posted: 01-Nov-2012 at 6:10pm
Well I don't need IoC in my testing. The crash happen when accessing the property Composition.Provider in the method CreateEntityManagerCore (from the EntityManagerProvider).

I will check the ICompositionProvider





Posted By: Walid
Date Posted: 02-Nov-2012 at 2:36am
it doesn't looks like Faking the ICompositionProvider is enough.

In the CreateEntityManagerCore you also access to EventFns which use the EventAggregatorLocator property. This one is coming from the PartLocator which use the composition to find the IEventAggregator. So if I fake the composition it can't it find the IEventAggregator. 

Afterthought, making MefCompositionProvider public would be much simple.


Posted By: mgood
Date Posted: 02-Nov-2012 at 10:10am
Walid,
Making MefCompositionProvider public would be the wrong thing after thinking about it again. Part of a good unit test is knowing exactly what the state is at the beginning of the test. It's hard to do that with MEF, because of the discovery mechanisms inherent to MEF. MEF will scoop up all your exports in the test project and after a while it becomes nearly impossible to control what's in the container leading to tests failing for unknown reasons or worse succeeding when they should fail.

Therefore at the beginning of each test, composition should be configured with a tightly controlled provider like so. 

        [TestInitialize]
        public void TestInitialize()
        {
            var provider = new TestCompositionProvider();
            provider.AddOrUpdateInstance<IEventAggregator>(new EventAggregator());
            Composition.SetProvider(provider);
        }

A possible implementation for TestCompositionProvider could look like follows. I will document this in the DRC as well.

    public class TestCompositionProvider : ICompositionProvider
    {
        private readonly Dictionary<Type, object> _container;

        public TestCompositionProvider()
        {
            _container = new Dictionary<Type, object>();    
        }

        public void AddOrUpdateInstance<T>(T instance)
        {
            _container[typeof(T)] = instance;
        }

        /// <summary>
        /// Returns a lazy instance of the specified type.
        /// </summary>
        /// <typeparam name="T">Type of the requested instance. </typeparam>
        public Lazy<T> GetInstance<T>() where T : class
        {
            return new Lazy<T>(() => (T) _container[typeof(T)]);
        }

        /// <summary>
        /// Returns an instance of the specified type.
        /// </summary>
        /// <typeparam name="T">Type of the requested instance. </typeparam>
        /// <returns>
        /// Null if instance is not present in the container. 
        /// </returns>
        public T TryGetInstance<T>() where T : class
        {
            object instance;
            if (!_container.TryGetValue(typeof(T), out instance))
                return null;

            return (T) instance;
        }

        /// <summary>
        /// Returns all instances of the specified type.
        /// </summary>
        /// <typeparam name="T">Type of the requested instances. </typeparam>
        public IEnumerable<T> GetInstances<T>() where T : class
        {
            return _container.Keys.Where(x => x == typeof(T)).Select(x => _container[x]).OfType<T>();
        }

        /// <summary>
        /// Returns a lazy instance that matches the specified name and type.
        /// </summary>
        /// <param name="serviceType">The type to match.</param><param name="contractName">The name to match.</param>
        public Lazy<object> GetInstance(Type serviceType, string contractName)
        {
            return new Lazy<object>(() => _container[serviceType]);
        }

        /// <summary>
        /// Returns an instance that matches the specified name and type.
        /// </summary>
        /// <param name="serviceType">The type to match.</param><param name="contractName">The name to match.</param>
        /// <returns>
        /// Null if instance is not present in the container. 
        /// </returns>
        public object TryGetInstance(Type serviceType, string contractName)
        {
            object instance;
            if (!_container.TryGetValue(serviceType, out instance))
                return null;

            return instance;
        }

        /// <summary>
        /// Returns all instances that match the specified name and type.
        /// </summary>
        /// <param name="serviceType">The type to match.</param><param name="contractName">The name to match.</param>
        public IEnumerable<object> GetInstances(Type serviceType, string contractName)
        {
            return _container.Keys.Where(x => x == serviceType).Select(x => _container[x]);
        }

        /// <summary>
        /// Returns a factory that creates new instances of the specified type.
        /// </summary>
        /// <typeparam name="T">Type of instance the factory creates. </typeparam>
        public ICompositionFactory<T> GetInstanceFactory<T>() where T : class
        {
            return new ActivatorFactory<T>();
        }

        /// <summary>
        /// Returns a factory that creates new instances of the specified type.
        /// </summary>
        /// <typeparam name="T">Type of instance the factory creates. </typeparam>
        /// <returns>
        /// Null if the container cannot provide a factory for the specified type. 
        /// </returns>
        public ICompositionFactory<T> TryGetInstanceFactory<T>() where T : class
        {
            return GetInstanceFactory<T>();
        }

        /// <summary>
        /// Manually performs property dependency injection on the provided instance.
        /// </summary>
        /// <param name="instance">The instance needing property injection. </param>
        public void BuildUp(object instance)
        {
            // Noop
        }
    }

    public class ActivatorFactory<T> : ICompositionFactory<T>
        where T : class
    {
        /// <summary>
        /// Creates new instance.
        /// </summary>
        public T NewInstance()
        {
            return Activator.CreateInstance<T>();
        }
    }




Print Page | Close Window