3

我试图测试SystemService.cs中的GetSystem(int id)方法返回正确的值,但似乎无法弄清楚如何让所有的东西都能很好地一起玩。看来不管我做什么,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。一些这种代码的,特别是在MockableDbSetWithIQueryablehttp://msdn.microsoft.com/en-US/data/dn314429

+0

你不能做'mockContext.Setup(c => c.Systems).Returns(data);'? –

回答

2

我能找到使用实体框架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); 
} 
0

.Find()发现正在恢复null因为这是System默认值。该收藏品不包含编号为id的物品。

.Find()List的方法。

我建议你使用LINQ的FirstOrDefault()

其原因是,你可以通过返回使用懒加载的IQueryable

+0

谢谢,我会尝试,但不Find()查询本地上下文,只有命中数据库,如果它找不到任何东西? –

+0

它看起来不可能直接实例化一个DbSet,因为它的构造函数被标记为protected。 –

+0

好的,我已经更新了我的答案。 Find()只是查询内存中的列表。我推荐使用'FirstOrDefault()' –