通用存储库在测试时不会将实体添加到上下文

时间:2016-03-30 14:17:45

标签: c# entity-framework unit-testing nsubstitute

我用EF创建GenericRepository并首次编写单元测试。 GetAll()Update()的测试已通过但Add()Delete()失败。为什么不Add?我把头发拉出来是因为它是一行代码,我无法弄明白。我使用EF数据库First,Nunit,Nsubstitute。

欢迎任何建议。

public class GenericDataRepository<T, C> : IGenericDataRepository<T, C> where T : class where C : DbContext, new() {

    protected C _context;
    protected IDbSet<T> _dbSet;

    public GenericDataRepository() {
        _context = new C();
        _dbSet = _context.Set<T>();
    }

    public GenericDataRepository(C context) {
        _context = context;
        _dbSet = context.Set<T>();
    }

    public virtual IQueryable<T> GetAll() {
        return _dbSet.AsQueryable<T>();
    }

    public virtual T Add(T entity) {
        return _dbSet.Add(entity);
    }

    public virtual void Update(T entity) {
        _context.Entry(entity).State = EntityState.Modified;
    }

    public virtual T Delete(T entity) {
        return _dbSet.Remove(entity);
    }

    public virtual void Save() {
        _context.SaveChanges();
    }

}

MyEntities

public partial class MyEntities : DbContext{
public MyEntities()
    : base("name=MyEntities")
{
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    throw new UnintentionalCodeFirstException();
}

public virtual DbSet<Customer> Cusotmers{ get; set; }

测试

 public static class NSubstituteUtils {
    public static DbSet<T> CreateMockDbSet<T>(IQueryable<T> data = null)
        where T : class {
        var mockSet = Substitute.For<DbSet<T>, IQueryable<T>>();
        mockSet.AsNoTracking().Returns(mockSet);

        if (data != null) {
            var queryable = data.AsQueryable();

            // setup all IQueryable methods using what you have from "data"
            ((IQueryable<T>)mockSet).Provider.Returns(data.Provider);
            ((IQueryable<T>)mockSet).Expression.Returns(data.Expression);
            ((IQueryable<T>)mockSet).ElementType.Returns(data.ElementType);
            ((IQueryable<T>)mockSet).GetEnumerator().Returns(data.GetEnumerator());
        }

        return mockSet;
    }
}

static IQueryable<Customer> data;
[SetUp]
    public void Init() {
        data = new List<Customer> {
            new Customer {
                CUSTOMER = "333",
                CUSTOMERNAME = "no name"
            },
            new Customer {
                CUSTOMER = "555",
                CUSTOMERNAME = "test name"
            }
        }.AsQueryable();
    }
[Test]
    public void Add_Should_AddGenericT() {

        var mockSet = NSubstituteUtils.CreateMockDbSet<Customer>(data);
        var mockContext = Substitute.For<MyEntities>();
        mockContext.Set<Customer>().Returns(mockSet);

        var repo = new GenericDataRepository<Customer, MyEntities>(mockContext);

        var customer = new Customer {
            CUSTOMER1 = "123",
            CUSTOMERNAME = "test name"
        };
        var result = repo.Add(customer);        // issue here: result returns null which should be a Customer
        repo.Save();

        var customerList = repo.GetAll().ToList();
        Assert.AreEqual(3, customerList.Count); // failed. Expected 3 but was 2
    }

1 个答案:

答案 0 :(得分:0)

您可以立即将数据变量定义为IQueryable,并使用它来模拟存储库中的_dbSet。

 data = new List<Customer> {
        new Customer {
            CUSTOMER = "333",
            CUSTOMERNAME = "no name"
        },
        new Customer {
            CUSTOMER = "555",
            CUSTOMERNAME = "test name"
        }
    }.AsQueryable();

因此,当您执行.Add()时,您实际上正在添加IQueryable,这是一个只读接口。

从数据定义中删除AsQueryable()并使用实际的List。