3

我正在尝试测试该GetSystem(int id)方法SystemService.cs是否返回正确的值,但似乎无法弄清楚如何让所有东西一起玩得很好。似乎无论我做什么,GetSystem()总是返回null。这是使用 Entity Framework 6。如果我将 GetSystem 的主体更改为 read _context.Systems.SingleOrDefault(s => s.Id = id),那么一切正常,但我真的很想使用Find().

测试这个的正确方法是什么?我在这个例子中使用 xUnit 和 Moq。SystemServiceTests.cs显示我当前使用的代码不起作用。

系统服务.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; }
  }
}

系统.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

4

2 回答 2

2

我能够找到使用 Entity Framework 6 测试所有内容的推荐方法。此推荐的资源可在http://msdn.microsoft.com/en-US/data/dn314431获得。

简而言之,需要为需要测试的每个位创建测试类。我最终做的是以下内容:

测试数据库集.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);
    }
}

测试上下文.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);
    }
}

系统服务.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);
    }
}

系统服务.cs

public interface ISystemService
{
    Models.System AddSystem(Models.System system);
    Models.System GetSystem(int id);
}
于 2013-10-29T16:01:57.317 回答
0

.Find()正在返回null,因为这是System. 该集合不包含具有 id 的项目id

.Find()是一种方法List

我建议你使用 LINQFirstOrDefault()

原因是,您可以通过返回一个IQueryable

于 2013-10-29T01:50:44.563 回答