locked
How to implement FakeObjectSet<T> : IObjectSet<T>, about EF 4 unit testing RRS feed

  • Question

  • Hello everyone,

    I just start to play with EF4 Beta 1 and I intended to write a unit test for my little program. The first thing is to mock a IObjectSet<T> as the datasource forthe unit test.

    I search carefully in the forum and find discussion between mighty_man and Diego B Vega [MSFT] at http://social.msdn.microsoft.com/Forums/en-US/adonetefx/thread/023ff3eb-c245-4ee8-94d8-4dbeaa071967/ . In this article, Diego kindly explain how to use repository and ObjectContext.

    In Diego's code snippet, I find he is using a class name "FakeObjectSet", which I suppose inherited from IObjectSet<T>. This is what I want. But I want to know the following:

    1. Is FakeObjectSet class shipped with .net framework or is it just some code I should implement myselft? (ok, you got me, I am a beginner about EF)

    2. If I should implement FakeObjectSet myself. It seems to be a lot of work to do because I have to implement many properties & method derived from IObjectSet<T> (really a lot of work). And I am not sure how I can implement every method correctly.

    3. Can anyone kindly demostrate how can I populate data into the the fake objectset?

    Thus, is there any detailed example (code) about how to mock the ObjectContext & ObjectSet? Please show some light on my path...

    Thanks a lot
    • Edited by Blade Leaf Wednesday, July 29, 2009 5:39 AM add new questions
    Wednesday, July 29, 2009 2:29 AM

Answers

  • Hello,

    This is actually a great question! FakeObjectSet<T> is not a class included in the framework but just a placeholder name for any fake implementation of the IObjectSet<T> interface. I can share with you right now a very simple version that we often use to implement fake ObjectContext classes for unit tests:

    using System;

    using System.Collections;

    using System.Collections.Generic;

    using System.Data.Objects;

    using System.Linq;

    using System.Linq.Expressions;

    using Microsoft.VisualStudio.TestTools.UnitTesting;

     

    namespace Testing

    {

     

        class FakeObjectSet<TEntity> : IObjectSet<TEntity> where TEntity : class

        {

            HashSet<TEntity> _data;

            IQueryable _query;

     

            public FakeObjectSet() : this(new List<TEntity>()) { }

     

            public FakeObjectSet(IEnumerable<TEntity> testData)

            {

                _data = new HashSet<TEntity>(testData);

                _query = _data.AsQueryable();

            }

     

            public void AddObject(TEntity item)

            {

                _data.Add(item);

            }

     

            public void DeleteObject(TEntity item)

            {

                _data.Remove(item);

            }

     

            public void Attach(TEntity item)

            {

                _data.Add(item);

            }

     

            IEnumerator IEnumerable.GetEnumerator()

            {

                return _data.GetEnumerator();

            }

     

            IEnumerator<TEntity> IEnumerable<TEntity>.GetEnumerator()

            {

                return _data.GetEnumerator();

            }

     

            Type IQueryable.ElementType

            {

                get { return _query.ElementType; }

            }

     

            Expression IQueryable.Expression

            {

                get { return _query.Expression; }

            }

     

            IQueryProvider IQueryable.Provider

            {

                get { return _query.Provider; }

            }

     

        }

    }

     

    You will find a brief sample on how to use this in the Sneak Peak blog post I wrote about Testability Improvements in EF 4, here.

    Hope this helps,

    Diego


    This posting is provided "AS IS" with no warranties, and confers no rights.
    Wednesday, July 29, 2009 7:55 AM
    Moderator
  • Dmitry,

    We currenlty don't have plans to introduce an IObjectQuery<T> interface. We migth consider doing so in order to expose additional methods of the ObjectQuery interface in such a way that is easier to fake, but on the other side we want to keep things simple. Regarding the lack of Include, this is relatively easy to overcome by defining an extension method on IQueryable<T>. See this thread for more details:

    http://social.msdn.microsoft.com/Forums/en-US/adonetefx/thread/023ff3eb-c245-4ee8-94d8-4dbeaa071967/

    Hope this helps,
    Diego
    This posting is provided "AS IS" with no warranties, and confers no rights.
    Monday, August 3, 2009 6:09 AM
    Moderator

All replies

  • Hello,

    This is actually a great question! FakeObjectSet<T> is not a class included in the framework but just a placeholder name for any fake implementation of the IObjectSet<T> interface. I can share with you right now a very simple version that we often use to implement fake ObjectContext classes for unit tests:

    using System;

    using System.Collections;

    using System.Collections.Generic;

    using System.Data.Objects;

    using System.Linq;

    using System.Linq.Expressions;

    using Microsoft.VisualStudio.TestTools.UnitTesting;

     

    namespace Testing

    {

     

        class FakeObjectSet<TEntity> : IObjectSet<TEntity> where TEntity : class

        {

            HashSet<TEntity> _data;

            IQueryable _query;

     

            public FakeObjectSet() : this(new List<TEntity>()) { }

     

            public FakeObjectSet(IEnumerable<TEntity> testData)

            {

                _data = new HashSet<TEntity>(testData);

                _query = _data.AsQueryable();

            }

     

            public void AddObject(TEntity item)

            {

                _data.Add(item);

            }

     

            public void DeleteObject(TEntity item)

            {

                _data.Remove(item);

            }

     

            public void Attach(TEntity item)

            {

                _data.Add(item);

            }

     

            IEnumerator IEnumerable.GetEnumerator()

            {

                return _data.GetEnumerator();

            }

     

            IEnumerator<TEntity> IEnumerable<TEntity>.GetEnumerator()

            {

                return _data.GetEnumerator();

            }

     

            Type IQueryable.ElementType

            {

                get { return _query.ElementType; }

            }

     

            Expression IQueryable.Expression

            {

                get { return _query.Expression; }

            }

     

            IQueryProvider IQueryable.Provider

            {

                get { return _query.Provider; }

            }

     

        }

    }

     

    You will find a brief sample on how to use this in the Sneak Peak blog post I wrote about Testability Improvements in EF 4, here.

    Hope this helps,

    Diego


    This posting is provided "AS IS" with no warranties, and confers no rights.
    Wednesday, July 29, 2009 7:55 AM
    Moderator
  • Thanks for your prompt reply, Diego.!

    I feel more confident now. I love this community ;-)
    Wednesday, July 29, 2009 8:03 AM
  • Glad to help! :)
    This posting is provided "AS IS" with no warranties, and confers no rights.
    Wednesday, July 29, 2009 8:09 AM
    Moderator
  • On a similar topic, is there a reason why ObjectQuery<T> does not implement an IObjectQuery<T> interface? It would be nice to be able to mock ObjectQuery<T> because IQueryable<T> does not always work (it is missing the Include method, etc).

    Thanks,
    Dmitry
    Thursday, July 30, 2009 3:34 PM
  • Dmitry,

    We currenlty don't have plans to introduce an IObjectQuery<T> interface. We migth consider doing so in order to expose additional methods of the ObjectQuery interface in such a way that is easier to fake, but on the other side we want to keep things simple. Regarding the lack of Include, this is relatively easy to overcome by defining an extension method on IQueryable<T>. See this thread for more details:

    http://social.msdn.microsoft.com/Forums/en-US/adonetefx/thread/023ff3eb-c245-4ee8-94d8-4dbeaa071967/

    Hope this helps,
    Diego
    This posting is provided "AS IS" with no warranties, and confers no rights.
    Monday, August 3, 2009 6:09 AM
    Moderator
  • Diego - The FakeObjectSet example above is a great code snippet.  Thank you!  I've tried it and it works great.

    However, my model has a number of relationships.  Can you elaborate on how you would fake not only the ObjectSets like above, but also how you'd fake the relationships between object types in the in-memory ObjectSets so that it's possible to fake a full EF model for testing purposes?
    Saturday, September 5, 2009 6:45 PM