Sof*_*are 7 c# asp.net-mvc unit-testing entity-framework moq
我正在为一个我正在努力的项目编写自动化测试,以便更熟悉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();
}
Run Code Online (Sandbox Code Playgroud)
这在正常在线环境中的应用程序运行时期间工作正常,但在测试方法中运行时会中断.我使用Moq来模拟DbContext中的DbSets并设置我的测试数据.
这是我的奇怪部分:我的单元测试运行正常(通过)但它们实际上并没有真正进入foreach循环 - 它在ChangeTracker.Entities()被访问时挂起并退出循环,向下跳转到_dbContext.SaveChanges().没有错误.
但是,在与我共享项目的朋友的机器上,ChangeTracker.Entities()访问时会收到SQLException .我确实在VS2015中检查了SQLExceptions,并且没有输出或其他异常指示.
结果StackTrace:
在System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject,UInt32 waitForMultipleObjectsTimeout,Boolean allowCreate,Boolean onlyOneCheckConnection,DbConnectionOptions userOptions,DbConnectionInternal&connection)....结果消息:
测试方法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
Run Code Online (Sandbox Code Playgroud)
我为自己找到了一个不太理想的解决方案,但足以让我继续前进。我DbContext.ChangeTracker.Entries()通过简单地向我的类添加一个抽象级别来绕过 API,该类扩展DbContext为MyApplicationDbContext:
public class MyApplicationDbContext : IdentityDbContext<MyApplicationUser>
{
//DbSets etc
public virtual IEnumerable<MyModelBase> AddedEntries
{
get
{
foreach (var entry in ChangeTracker.Entries().Where(entry => entry.State == EntityState.Added))
{
MyModelBase model = entry.Entity as MyModelBase;
if (model != null)
{
yield return model;
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
MyApplicationDbContext.AddedEntries这样我仍然可以通过调用而不是迭代问题陈述中描述的业务逻辑的 Entries() MyApplicationDbContext.ChangeTracker.Entries()。但是,由于我创建了该属性virtual,因此我可以使用起订量设置退货:
List<SomeModel> addedEntries = new List<SomeModel>();
addedEntries.add(someModelWhichWillBeAddedByTheController);
mockContext.Setup(context => context.AddedEntries).Returns(addedEntries);
Run Code Online (Sandbox Code Playgroud)
这样控制器将观察someModelWhichWillBeAddedByTheController何时AddedEntries使用该属性。缺点是我无法测试DbContext.ChangeTracker.Entries()实际业务逻辑中使用的代码,但稍后我可以通过使用测试数据库实施集成测试来实现这一点。
我始终无法找到被SQLException扔到一台机器上而不是另一台机器上的原因。
| 归档时间: |
|
| 查看次数: |
1870 次 |
| 最近记录: |