【发布时间】:2016-02-29 17:09:37
【问题描述】:
我正在为我一直从事的项目编写自动化测试,以便更加熟悉 MVC、EntityFramework(代码优先)、单元测试和 Moq。
我的Repository 类中有一个部分,它设置我的模型的LastModified 字段,每当Repository.SaveChanges() 被这样工作的控制器调用时(MyModelBase 是一个基类):
public void RepoSaveChanges()
{
foreach(var entry in _dbContext.ChangeTracker.Entities().Where(e => e.State == EntityState.Modified))
{
MyModelBase model = entry.Entity as MyModelBase;
if (model != null)
{
model.LastModified = DateTime.Now;
}
}
_dbContext.SaveChanges();
}
这在正常在线环境中的应用程序运行时工作正常,但在测试方法中运行时会中断。我使用 Moq 在 DbContext 中模拟 DbSet 并设置我的测试数据。
这对我来说很奇怪:
我的单元测试运行良好(通过),但它们实际上并没有进入foreach 循环——当访问ChangeTracker.Entities() 并退出循环时它挂起,跳到_dbContext.SaveChanges()。没有错误。
但是,在与我共享项目的朋友的机器上,当访问ChangeTracker.Entities() 时,他得到了一个 SQLException。我确实检查了在 VS2015 中抛出的 SQLExceptions,并且我这边没有输出或其他异常指示。
结果堆栈跟踪:
在 System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject,UInt32 waitForMultipleObjectsTimeout,布尔allowCreate,布尔onlyOneCheckConnection,DbConnectionOptions userOptions,DbConnectionInternal& 连接) ....结果消息:
测试方法 MyProject.Tests.TestClasses.MyControllerTests.TestCreate 抛出异常: System.Data.SqlClient.SqlException:建立与 SQL Server 的连接时发生与网络相关或特定于实例的错误。服务器未找到或无法访问。验证实例名称是否正确以及 SQL Server 是否配置为允许远程连接。 (提供者:SQL 网络接口,错误:26 - 错误定位服务器/指定的实例)
最后,我的问题是:有没有办法使用 Moq 来模拟 ChangeTracker(我怀疑不是来自先前的调查),或者我可以对我的 RepoSaveChanges() 采取另一种方法来自动设置属性?如果不访问ChangeTracker.Entities(),我将需要更新逻辑来为每个拥有它的模型类型设置LastModified 字段。同样,我想避免使用该 API/框架的一部分,因为顽固的测试并不理想。
有没有人知道为什么我的机器上没有抛出/无法捕获 SQLException?或者关于如何在单元测试中使用ChangeTracker.Entities() 的任何建议?作为最后的手段,我只会在我的所有模型和控制器中单独设置 LastModified 属性。
更新: 已请求更多示例代码,因此让我进一步详细说明。我使用 moq 模拟 DbContext,然后模拟 DbContext 中包含的 DbSet 对象:
var mockContext = new Mock<MyApplicationDbContext>(); //MyApplicationDbContext extends DbContext
Person p = new Person();
p.Name = "Bob";
p.Employer = "Superstore";
List<Person> list = new List<Person>();
list.Add(p);
var queryable = list.AsQueryable();
Mock<DbSet<Person>> mockPersonSet = new Mock<DbSet<Person>>();
mockPersonSet.As<IQueryable<Person>>().Setup(set => set.Provider).Returns(queryable.Provider);
mockPersonSet.As<IQueryable<Person>>().Setup(set => set.Expression).Returns(queryable.Expression);
mockPersonSet.As<IQueryable<Person>>().Setup(set => set.ElementType).Returns(queryable.ElementType);
mockPersonSet.As<IQueryable<Person>>().Setup(set => set.GetEnumerator()).Returns(() => queryable.GetEnumerator());
DbSet<Person> dbSet = mockPersonSet.Object as DbSet<Person>;
mockPersonSet.Setup(set => set.Local).Returns(dbSet.Local);
mockContext.Setup(context => context.Set<Person>()).Returns(mockPersonSet.Object);
mockContext.Setup(context => context.Persons).Returns(mockPersonSet.Object));
//Create the repo using the mock data context I created
PersonRepository repo = new PersonRepository(mockContext.Object);
//Then finally create the controller and perform the test
PersonController controller = new PersonController(repo);
var result = controller.Create(someEmployerID); //Sometimes throws an SQLException when DbContext.SaveChanges() is called
【问题讨论】:
-
这是什么版本的EF?
-
@E-Bat EF 版本 6.1.3
标签: c# asp.net-mvc entity-framework unit-testing moq