Метод поиска метода Entity Framework

asp.net-web-api c# entity-framework entity-framework-6 unit-testing

Вопрос

Я пытаюсь проверить, что метод GetSystem(int id) в SystemService.cs возвращает правильное значение, но, похоже, не может понять, как заставить все хорошо играть вместе. Кажется, что независимо от того, что я делаю, GetSystem() всегда возвращает null. Это использует Entity Framework 6. Если я изменил тело GetSystem на чтение _context.Systems.SingleOrDefault(s => s.Id = id) , тогда все будет работать правильно, но мне бы очень хотелось использовать Find() .

Каков правильный способ проверить это? В этом примере я использую xUnit и Moq. SystemServiceTests.cs показывает код, который я сейчас использую, который не работает.

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. Некоторая часть кода для этого, в частности, MockableDbSetWithIQueryable была найдена по адресу http://msdn.microsoft.com/en-US/data/dn314429

Принятый ответ

Я смог найти рекомендуемый способ протестировать все, используя Entity Framework 6. Ресурс для этой рекомендации доступен по адресу http://msdn.microsoft.com/en-US/data/dn314431 .

Вкратце, для каждого бита, который необходимо протестировать, необходимо создать тестовые классы. То, что я закончил, это следующее:

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);
}

Популярные ответы

.Find() возвращает значение null поскольку это значение по умолчанию для System . Коллекция не содержит элемент с id id .

.Find() - метод List .

Я предлагаю вам использовать FirstOrDefault() LINQ's FirstOrDefault()

Причина в том, что вы можете использовать ленивую загрузку, возвращая IQueryable




Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему