Using Duplicates with DbEntityEntry and DbPropertyEntry

I am using new test pairs in EF6 as described here from MSDN . VS2013 with Moq and nUnit. Everything was fine until I had to do something like this:

var myFoo = context.Foos.Find(id);

and then:

myFoo.Name = "Bar";

and then:

context.Entry(myFoo).Property("Name").IsModified = true;

At this point, I get the error:

Additional information: Member 'IsModified' cannot be called on the 'Name' property because an object of type 'Foo' does not exist in the context. To add an object to the context, it will call the add or attach DbSet method.

Although, when I examine "Foos" in context with AddWatch, I can see all the items I added before running the test. So they are.

I created a FakeDbSet (or TestDbSet) from the article. I put each FakeDbSet in a FakeContext in a constructor where each one is initialized. Like this:

Foos = new FakeDbSet<Foo>();

My question is, is it possible to work with FakeDbSet and FakeContext with a double test script in such a way that I can access DbEntityEntry and DBPropertyEntry from the test double? Thank!

+3


source to share


2 answers


I can see all the items that I added before running the test. So they are there.

Effectively, you've only added items to ObservableCollection

. The method context.Entry

reaches a much deeper meaning. This requires the change tracker to actively participate in adding, modifying, and removing objects. If you want to mock this change tracker ObjectStateManager

(ignoring the fact that it is not meant to be mocked at all), good luck! He received over 4000 lines of code.

To be honest, I don't understand all these blogs and articles about EF mocking. The numerous differences between LINQ objects and LINQ are enough to include . These false contexts DbSet

create a completely new universe, which is itself a source of error. I decided to make an integration test only when and where EF is involved in my code. A working end-to-end test gives me a solid feeling that everything is in order. A unit test (fake EF). (Others do, don't get me wrong).

But suppose you are willing to take risks in mockery anyway DbContext.Entry<T>

. Too bad, impossible.



  • Method is not virtual
  • It returns DbEntityEntry<T>

    , a class with an inner constructor, which is a wrapper InternalEntityEntry

    , which is an inner class. And by the way, it DbEntityEntry

    doesn't implement the interface.

So to answer your question

Is it possible (...) to have access to DbEntityEntry and DBPropertyEntry from the test double?

No, EF mocking hooks are only very superficial, you don't even get close to how EF actually works.

+4


source


Just abstract it out. If you are working with the interface by creating your own doubles, put the changed material in a separate method. My interface and implementation (created by EF, but I changed the template) looks like this:



//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Manual changes to this file may cause unexpected behavior in your application.
//     Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace Model
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;

    public interface IOmt
    {
        DbSet<DatabaseOmtObjectWhatever> DatabaseOmtObjectWhatever { get; set; }
        int SaveChanges();
        void SetModified(object entity);
        void SetAdded(object entity);
    }

    public partial class Omt : DbContext, IOmt
    {
        public Omt()
            : base("name=Omt")
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }

        public virtual DbSet<DatabaseOmtObjectWhatever> DatabaseOmtObjectWhatever { get; set; }

        public void SetModified(object entity)
        {
            Entry(entity).State = EntityState.Modified;
        }
        public void SetAdded(object entity)
        {
            Entry(entity).State = EntityState.Added;
        }
    }
}

      

0


source







All Articles