Question

I'm attempting to verify that theGetSystem(int id) approach inSystemService.cs returns the right value, but can't seem to get everything to work together smoothly. It appears that whatever I do,GetSystem() returns nil each time. Entity Framework 6 is being used here. If I modify GetSystem's body to read_context.Systems.SingleOrDefault(s => s.Id = id) everything will function as intended, however I'd really prefer to useFind() .

How exactly should this be tested? In this illustration, I'm utilizing xUnit and Moq.SystemServiceTests.cs demonstrates the problematic code I'm currently utilizing.

SystemService.cs

namespace MyProject.Services
{
  public class SystemService
  {
    private readonly MyContext _context;

    public SystemService(MyContext context)
    {
      _context = context;
    }

    public Models.System GetSystem(int id)
    {
      return _context.Systems.Find(id);
    }
  }
}

SystemServiceTests.cs

namespace MyProject.Tests.Unit
{
  public class SystemServiceTests
  {
    [Fact]
    public void GetSystemReturnsFromContext()
    {
      var data = new List<Models.System> {
        new Models.System { Id = 1, Name = "test 1" },
        new Models.System { Id = 2, Name = "test 2" }
      }.AsQueryable();

      var mockContext = new Mock<MyContext>();

      var mockSet = new Mock<MockableDbSetWithIQueryable<Models.System>>();
      mockContext.Setup(c => c.Systems).Returns(mockSet.Object);

      mockSet.Setup(m => m.Provider).Returns(data.Provider);
      mockSet.Setup(m => m.Expression).Returns(data.Expression);
      mockSet.Setup(m => m.ElementType).Returns(data.ElementType);
      mockSet.Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

      var service = new SystemService(mockContext.Object);
      var system = service.GetSystem(1);

      Assert.NotNull(system); // This is always null
    }
  }
}

MyContext.cs

namespace MyProject.Models
{
  public class MyContext : DbContext
  {
    public MyContext()
      : base("DefaultConnection")
    {
    }

    public virtual DbSet<Models.System> Systems { get; set; }
  }
}

System.cs

namespace MyProject.Models
{
  public class System
  {
    public int Id { get; set; }
    public string Name { get; set; }
  }
}

MockableDbSetWithIQueryable.cs

namespace MyProject.Tests.Helpers
{
  public abstract class MockableDbSetWithIQueryable<T> : DbSet<T>, IQueryable
    where T : class
  {
    public abstract IEnumerator<T> GetEnumerator();
    public abstract Expression Expression { get; }
    public abstract Type ElementType { get; }
    public abstract IQueryProvider Provider { get; }
  }
}

PS. Some of the specific code for thisMockableDbSetWithIQueryable was discovered at 74-zzz

1
3
10/29/2013 1:30:37 AM

Accepted Answer

Using Entity Framework 6, I was able to discover the recommended method to test everything. The source for this advice can be found at http://msdn.microsoft.com/en-US/data/dn314431.

For each part that needs to be tested, test classes must be created, in a nutshell. What I ultimately did was as follows:

TestDbSet.cs

public class TestDbSet<TEntity> : DbSet<TEntity>, IQueryable, IEnumerable<TEntity>
    where TEntity : class
{
    ObservableCollection<TEntity> _data;
    IQueryable _query;

    public TestDbSet()
    {
        _data = new ObservableCollection<TEntity>();
        _query = _data.AsQueryable();
    }

    public override TEntity Add(TEntity item)
    {
        _data.Add(item);
        return item;
    }

    public override TEntity Remove(TEntity item)
    {
        _data.Remove(item);
        return item;
    }

    public override TEntity Attach(TEntity item)
    {
        _data.Add(item);
        return item;
    }

    public override TEntity Create()
    {
        return Activator.CreateInstance<TEntity>();
    }

    public override TDerivedEntity Create<TDerivedEntity>()
    {
        return Activator.CreateInstance<TDerivedEntity>();
    }

    public override ObservableCollection<TEntity> Local
    {
        get
        {
            return _data;
        }
    }

    Type IQueryable.ElementType
    {
        get { return _query.ElementType; }
    }

    Expression IQueryable.Expression
    {
        get { return _query.Expression; }
    }

    IQueryProvider IQueryable.Provider
    {
        get { return _query.Provider; }
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return _data.GetEnumerator();
    }

    IEnumerator<TEntity> IEnumerable<TEntity>.GetEnumerator()
    {
        return _data.GetEnumerator();
    }
}

TestSystemDbSet.cs

class TestSystemDbSet : TestDbSet<Models.System>
{
    public override Models.System Find(params object[] keyValues)
    {
        var id = (int)keyValues.Single();
        return this.SingleOrDefault(s => s.Id == id);
    }
}

TestContext.cs

public class TestContext: IContext
{
    public TestContext()
    {
        this.Systems = new TestSystemDbSet();
    }

    public DbSet<Models.System> Systems { get; set; }

    public int SaveChangesCount { get; private set; }
    public int SaveChanges()
    {
        this.SaveChangesCount++;
        return 1;
    }
}

SystemServiceTests.cs

public class SystemServiceTests
{
    [Fact]
    public void GetSystemReturnsFromContext()
    {
        var context = new TestContext();
        context.Systems.Add(new Models.System { Id = 1, Name = "System 1" });
        context.Systems.Add(new Models.System { Id = 2, Name = "System 2" });
        context.Systems.Add(new Models.System { Id = 3, Name = "System 3" });

        var service = new SystemService(context);
        var system = service.GetSystem(2);

        Assert.NotNull(system);
        Assert.Equal(2, system.Id);
        Assert.Equal("System 2", system.Name);
    }
}

SystemService.cs

public class SystemService : ISystemService
{
    private readonly IContext _context;

    public SystemService(IContext context)
    {
        _context = context;
    }

    public Models.System AddSystem(Models.System system)
    {
        var s = _context.Systems.Add(system);
        _context.SaveChanges();

        return s;
    }

    public Models.System GetSystem(int id)
    {
        return _context.Systems.Find(id);
    }
}

ISystemService.cs

public interface ISystemService
{
    Models.System AddSystem(Models.System system);
    Models.System GetSystem(int id);
}
2
10/29/2013 4:01:57 PM

Popular Answer

.Find() is relocatingnull since that is the default setting forSystem The collection lacks an object with an id.id .

.Find() is a process forList .

I advise utilizing LINQ'sFirstOrDefault()

The reason being that by returning an object, you may employ lazy loading.IQueryable



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow