New Posts New Posts RSS Feed: Silverlight Unit testing and cocktail 2 beta
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Silverlight Unit testing and cocktail 2 beta

 Post Reply Post Reply
Author
Walid View Drop Down
Senior Member
Senior Member
Avatar

Joined: 14-Nov-2010
Posts: 161
Post Options Post Options   Quote Walid Quote  Post ReplyReply Direct Link To This Post Topic: Silverlight Unit testing and cocktail 2 beta
    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 ?
Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post 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.
Back to Top
Walid View Drop Down
Senior Member
Senior Member
Avatar

Joined: 14-Nov-2010
Posts: 161
Post Options Post Options   Quote Walid Quote  Post ReplyReply Direct Link To This Post 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



Back to Top
Walid View Drop Down
Senior Member
Senior Member
Avatar

Joined: 14-Nov-2010
Posts: 161
Post Options Post Options   Quote Walid Quote  Post ReplyReply Direct Link To This Post 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.
Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post 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>();
        }
    }

Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down