C# 通用存储库不';测试时不要将实体添加到上下文中

C# 通用存储库不';测试时不要将实体添加到上下文中,c#,entity-framework,unit-testing,nsubstitute,C#,Entity Framework,Unit Testing,Nsubstitute,我正在用EF创建一个通用的存储库,并第一次编写单元测试。对GetAll()和Update()的测试通过,但Add()和Delete()失败。为什么它不添加?我很紧张,因为这是一行代码,我想不出来。我先用EF数据库,Nunit,Nsubstitute 欢迎任何建议 public class GenericDataRepository<T, C> : IGenericDataRepository<T, C> where T : class where C : DbContex

我正在用EF创建一个通用的存储库,并第一次编写单元测试。对
GetAll()
Update()
的测试通过,但
Add()
Delete()
失败。为什么它不添加?我很紧张,因为这是一行代码,我想不出来。我先用EF数据库,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();
    }

}
公共类GenericDataRepository:IGenericDataRepository其中T:class其中C:DbContext,new(){
受保护的C_上下文;
受保护IDbSet _dbSet;
公共GenericDataRepository(){
_context=newc();
_dbSet=_context.Set();
}
公共GenericDataRepository(C上下文){
_上下文=上下文;
_dbSet=context.Set();
}
公共虚拟IQueryable GetAll(){
返回_dbSet.AsQueryable();
}
公共虚拟T添加(T实体){
返回_dbSet.Add(实体);
}
公共虚拟无效更新(T实体){
_context.Entry(entity.State=EntityState.Modified;
}
公共虚拟T删除(T实体){
返回_dbSet.Remove(实体);
}
公共虚拟void Save(){
_SaveChanges();
}
}
myenties

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
    }
公共部分类myenties:DbContext{
公共慈善机构()
:base(“name=MyEntities”)
{
}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
抛出新代码FirstException();
}
公共虚拟数据库集Cusotmers{get;set;}
测试

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
    }
公共静态类NSSubstituteUtils{
公共静态DbSet CreateMockDbSet(IQueryable data=null)
T:在哪里上课{
var mockSet=Substitute.For();
AsNoTracking()返回(mockSet);
如果(数据!=null){
var queryable=data.AsQueryable();
//使用“数据”中的内容设置所有IQueryable方法
((IQueryable)mockSet.Provider.Returns(data.Provider);
((IQueryable)mockSet.Expression.Returns(data.Expression);
((IQueryable)mockSet.ElementType.Returns(data.ElementType);
((IQueryable)mockSet.GetEnumerator()。返回(data.GetEnumerator());
}
返回模拟集;
}
}
静态可查询数据;
[设置]
公共void Init(){
数据=新列表{
新客户{
CUSTOMER=“333”,
CUSTOMERNAME=“没有名字”
},
新客户{
CUSTOMER=“555”,
CUSTOMERNAME=“测试名称”
}
}.AsQueryable();
}
[测试]
public void Add_Should_AddGenericT(){
var mockSet=NSubstituteUtils.CreateMockDbSet(数据);
var mockContext=Substitute.For();
mockContext.Set().返回(mockSet);
var repo=新的GenericDataRepository(mockContext);
var客户=新客户{
CUSTOMER1=“123”,
CUSTOMERNAME=“测试名称”
};
var result=repo.Add(customer);//此处的问题:result返回null,该值应为客户
repo.Save();
var customerList=repo.GetAll().ToList();
Assert.AreEqual(3,customerList.Count);//失败。应为3,但为2
}

您正在将这里的数据变量定义为IQueryable,并使用它模拟存储库中的_dbSet

 data = new List<Customer> {
        new Customer {
            CUSTOMER = "333",
            CUSTOMERNAME = "no name"
        },
        new Customer {
            CUSTOMER = "555",
            CUSTOMERNAME = "test name"
        }
    }.AsQueryable();
data=新列表{
新客户{
CUSTOMER=“333”,
CUSTOMERNAME=“没有名字”
},
新客户{
CUSTOMER=“555”,
CUSTOMERNAME=“测试名称”
}
}.AsQueryable();
因此,当您在执行.Add()时,实际上是在向IQueryable添加一个只读接口


从数据定义中去掉AsQueryable(),并使用实际列表。

您正在将这里的数据变量定义为IQueryable,并使用它模拟存储库中的_dbSet

 data = new List<Customer> {
        new Customer {
            CUSTOMER = "333",
            CUSTOMERNAME = "no name"
        },
        new Customer {
            CUSTOMER = "555",
            CUSTOMERNAME = "test name"
        }
    }.AsQueryable();
data=新列表{
新客户{
CUSTOMER=“333”,
CUSTOMERNAME=“没有名字”
},
新客户{
CUSTOMER=“555”,
CUSTOMERNAME=“测试名称”
}
}.AsQueryable();
因此,当您在执行.Add()时,实际上是在向IQueryable添加一个只读接口


从数据定义中删除AsQueryable(),并使用实际列表。

您的
Customer
类型是否与相应的实体类型匹配?我没有在
Customer
中包含所有属性。某些字段不能为空。但是
repo.Save()
没有引发异常。很抱歉,要澄清的是,
客户
类型必须与实体框架中映射到表的类型相同。您是如何映射上下文的?您是先使用数据库还是先使用代码?先使用数据库。我可以在模拟/测试部分之外添加客户。我添加了
MyEntities
这是一个非常糟糕的存储库实现。你为什么要创建它?你认为你通过使用它而不是实体框架接口实现了什么?存储库模式的目的是通过创建一个抽象来降低复杂性。你的实现没有做到这两个。你的
客户
t类型是否与相应的实体类型匹配?我没有包括
Customer
中的所有属性。某些字段不能为空。但是
repo.Save()
没有引发异常。很抱歉,要澄清的是,
客户
类型必须与实体框架中映射到表的类型相同。您是如何映射上下文的?您是先使用数据库还是先使用代码?先使用数据库。我可以在模拟/测试部分之外添加客户。我添加了
MyEntities
这是一个非常糟糕的存储库实现。你为什么要创建它?你认为你取得了什么成就