Asp.net mvc 实体框架4.1集成单元测试
首先,有几个注意事项: 我们正在建设一个中小型系统,预计寿命为2-5年,相对较短。该系统正在使用实体框架4.1、代码优先、MVC3进行开发。我们正在努力推动我们的团队走向单元测试/TDD。这是我们没有做过的事情,但我们认识到它的价值,因此正在朝着这个方向迈出初步的步伐 考虑到所有这些,我们决定使用VisualStudio2010的内置测试框架构建单元测试。我们没有使用存储库模式或模拟。这是为了减少构建单元测试的复杂性和时间。每个单元测试实际上更像是一个集成测试——我们有一个“测试”数据库,它在每次测试运行时都会初始化,每个测试都使用视图使用的相同控制器,以便尽可能接近系统的真实行为 在评论或回答此问题时,请不要攻击此方法。我很清楚,这不是TDD最纯粹的形式,也不是测试工作单元的理想模式。我们这样做是为了让我们的脚沾湿这项技术,并试图在构建单元测试的时间方面获得最大的回报 问题是: 我们正在构建大量的单元测试,这些测试通过控制器存储对象,然后通过控制器从数据库中检索对象,以验证它是否正确存储,以及它是否以我们期望的方式通过控制器返回。以下是一个例子:Asp.net mvc 实体框架4.1集成单元测试,asp.net-mvc,unit-testing,asp.net-mvc-3,tdd,ef-code-first,Asp.net Mvc,Unit Testing,Asp.net Mvc 3,Tdd,Ef Code First,首先,有几个注意事项: 我们正在建设一个中小型系统,预计寿命为2-5年,相对较短。该系统正在使用实体框架4.1、代码优先、MVC3进行开发。我们正在努力推动我们的团队走向单元测试/TDD。这是我们没有做过的事情,但我们认识到它的价值,因此正在朝着这个方向迈出初步的步伐 考虑到所有这些,我们决定使用VisualStudio2010的内置测试框架构建单元测试。我们没有使用存储库模式或模拟。这是为了减少构建单元测试的复杂性和时间。每个单元测试实际上更像是一个集成测试——我们有一个“测试”数据库,它在每
[TestMethod]
public void Edit_Post_Saves_OperatingCompany_In_DB_When_OperatingCompany_Is_Valid()
{
OperatingCompany opco = new OperatingCompany();
opco.Name = "OpCo - Edit Post - Valid - DB Save";
controller = new OperatingCompanyController();
controller.Create(opco);
Guid opcoid = opco.Id;
controller = new OperatingCompanyController();
opco = (OperatingCompany) ((ViewResult)controller.Edit(opcoid)).Model;
opco.Name = "Edit - OpCo - Edit Post - Valid - DB Save";
controller = new OperatingCompanyController();
HelperMethods.AddValidationResultsToModelState(opco, controller);
controller.Edit(opco);
controller = new OperatingCompanyController();
ViewResult result = controller.Index();
Assert.IsTrue(((IEnumerable<OperatingCompany>)result.Model).Contains(opco));
}
我们得到的错误是:
测试方法WebObjects.Tests.Controller.OperatingCompanyControllerTest.Edit\u Post\u在\u OperatingCompany\u有效时将\u OperatingCompany\u保存在\u DB\u中引发异常:
System.InvalidOperationException:一个实体对象不能被IEntityChangeTracker的多个实例引用
我很确定这是因为所讨论的实体没有从第一个控制器的上下文中分离出来,当我们重新实例化它并尝试编辑同一个实体时,它认为另一个上下文仍然控制着它。我们重新实例化控制器的原因是为了确保实体从数据库中回调,而不仅仅是从DbContext的缓存中返回。如果我在这里出错,请纠正我,但我相信如果我们不重新实例化,就会发生这种情况
我们能够通过在每次调用SaveChanges之后显式地将每个对象从上下文中分离,以及在通过控制器中的上下文查询对象时分离,来实现这一点,但我不想这样做只是为了让单元测试正常工作,而且我确信这将对性能造成重大影响
问题是:
是否有更好的方法对我们的控制器执行这种类型的集成测试?在将其传递给Editpost操作之前,您可以尝试创建opco的新实例。要简化副本的创建,您可以使用AutoMapper,例如:
Mapper.CreateMap<OperatingCompany, OperatingCompany>();
opco = Mapper.Map<OperatingCompany, OperatingCompany>(opco);