测试实体框架查找方法
本文关键字:方法 查找 框架 实体 测试 | 更新日期: 2023-09-27 18:37:24
我正在尝试测试SystemService.cs
中的GetSystem(int id)
方法返回正确的值,但似乎无法弄清楚如何让所有内容很好地结合在一起。似乎无论我做什么,GetSystem()
总是返回 null。这是使用实体框架 6。如果我更改 GetSystem 的主体以读取_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);
}
}
}
系统服务测试.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
}
}
}
我的上下文.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; }
}
}
附言。这方面的一些代码,特别是MockableDbSetWithIQueryable
代码,可以在 http://msdn.microsoft.com/en-US/data/dn314429
我能够找到使用实体框架 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);
}
}
测试上下文.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;
}
}
系统服务测试.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);
}
}
ISystemService.cs
public interface ISystemService
{
Models.System AddSystem(Models.System system);
Models.System GetSystem(int id);
}
.Find()
返回null
,因为这是System
的默认值。该集合不包含 ID 为 id
的项。
.Find()
是一种List
的方法。
我建议你使用LINQ的FirstOrDefault()
原因是,您可以通过返回IQueryable
来使用延迟加载