DbContext.Set<TEntity>() 在测试框架中返回垃圾数据代理
DbContext.Set<TEntity>() in Test Framework Returning Garbage Data Proxies
在我的测试框架中,当我调用 DbContext.Set<FakeClass1>()
时,我返回了一大堆垃圾数据(看起来是代理,因为它们是 System.Data.Entity.Dynamicproxies
)。如果我调用 DbContext.FakeClass1s
,我不会得到任何这些垃圾。
问题是,在通用的 Repository bass class 中,我调用 DbContext.Set<TEntity>()
因为显然它是减少代码的好东西。但是我需要为我的测试框架解决这个问题。
这是测试代码 - 结果应该是计数 2,因为只有两个被添加到 DbContext DbSet。
[TestMethod]
public void FindAll_Should_Work()
{
// Arrange
var dbContext = new FakeDbContext();
// Act
var s1= dbContext.FakeClass1s;
var s2 = dbContext.Set<FakeClass1>();
// Assert
Assert.AreEqual(2, s1.Count());
Assert.AreEqual(2, s2.Count());
}
s1
的结果是正确的。但是对于 s2
,结果是 14。
这是 FakeDbContext 的代码:
public class FakeDbContext : System.Data.Entity.DbContext
{
public DbSet<FakeClass1> FakeClass1s { get; set; }
public DbSet<FakeClass2> FakeClass2s { get; set; }
public FakeDbContext()
{
PopulateData();
}
private void PopulateData()
{
var f11 = new FakeClass1()
{
ID = 1,
Name = "One"
};
var f12 = new FakeClass1()
{
ID = 2,
Name = "Two"
};
FakeClass1s.Add(f11);
FakeClass1s.Add(f12);
}
}
此外,这些额外的结果实际上是似乎在其他测试的整个 运行 过程中累积的数据。在那里我找到了具有来自其他测试的值的对象。即使我 运行 孤立地进行此测试,并注释掉使用和测试这些其他对象的代码,也会出现这种情况。所以有些东西被记住了。
此外,看当地人 window 似乎 s1
确实是一个 DbSet<FakeClass1>
,其中 s2
是一个查询 (?):
编辑:标记了正确答案,但要在这里注意:问题继承自 System.Data.Entity.DbContext。显然,正如 andrerpena 善意建议的那样,要做的只是实现接口而不是从这个 class 派生。一旦我停止从 System.Data.Entity.DbContext.
继承,奇怪的行为就消失了
您所说的垃圾是您在 PopulateData
中创建的实体,并且以某种方式保存在数据库中。这些 dynamicProxies
是继承自 FakeClass1
和 FakeClass2
的动态类型的对象。 EF 创建代理的原因是您可以从延迟加载和适当的属性同步中受益。
您的 FakeDbContext
继承自真实的 DbContext
。这会导致实体实际上被持久化并从商店中检索(您必须调用 SaveChanges 才能发生这种情况,但您可能正在这样做或过去做过)。这不是一个好的做法。
人们通常做的是创建一个 IDbContext
接口,然后专门为您的上下文创建另一个接口。类似于 IYourAppContext
.
在我的测试框架中,当我调用 DbContext.Set<FakeClass1>()
时,我返回了一大堆垃圾数据(看起来是代理,因为它们是 System.Data.Entity.Dynamicproxies
)。如果我调用 DbContext.FakeClass1s
,我不会得到任何这些垃圾。
问题是,在通用的 Repository bass class 中,我调用 DbContext.Set<TEntity>()
因为显然它是减少代码的好东西。但是我需要为我的测试框架解决这个问题。
这是测试代码 - 结果应该是计数 2,因为只有两个被添加到 DbContext DbSet。
[TestMethod]
public void FindAll_Should_Work()
{
// Arrange
var dbContext = new FakeDbContext();
// Act
var s1= dbContext.FakeClass1s;
var s2 = dbContext.Set<FakeClass1>();
// Assert
Assert.AreEqual(2, s1.Count());
Assert.AreEqual(2, s2.Count());
}
s1
的结果是正确的。但是对于 s2
,结果是 14。
这是 FakeDbContext 的代码:
public class FakeDbContext : System.Data.Entity.DbContext
{
public DbSet<FakeClass1> FakeClass1s { get; set; }
public DbSet<FakeClass2> FakeClass2s { get; set; }
public FakeDbContext()
{
PopulateData();
}
private void PopulateData()
{
var f11 = new FakeClass1()
{
ID = 1,
Name = "One"
};
var f12 = new FakeClass1()
{
ID = 2,
Name = "Two"
};
FakeClass1s.Add(f11);
FakeClass1s.Add(f12);
}
}
此外,这些额外的结果实际上是似乎在其他测试的整个 运行 过程中累积的数据。在那里我找到了具有来自其他测试的值的对象。即使我 运行 孤立地进行此测试,并注释掉使用和测试这些其他对象的代码,也会出现这种情况。所以有些东西被记住了。
此外,看当地人 window 似乎 s1
确实是一个 DbSet<FakeClass1>
,其中 s2
是一个查询 (?):
编辑:标记了正确答案,但要在这里注意:问题继承自 System.Data.Entity.DbContext。显然,正如 andrerpena 善意建议的那样,要做的只是实现接口而不是从这个 class 派生。一旦我停止从 System.Data.Entity.DbContext.
继承,奇怪的行为就消失了您所说的垃圾是您在 PopulateData
中创建的实体,并且以某种方式保存在数据库中。这些 dynamicProxies
是继承自 FakeClass1
和 FakeClass2
的动态类型的对象。 EF 创建代理的原因是您可以从延迟加载和适当的属性同步中受益。
您的 FakeDbContext
继承自真实的 DbContext
。这会导致实体实际上被持久化并从商店中检索(您必须调用 SaveChanges 才能发生这种情况,但您可能正在这样做或过去做过)。这不是一个好的做法。
人们通常做的是创建一个 IDbContext
接口,然后专门为您的上下文创建另一个接口。类似于 IYourAppContext
.