ASP.NET MVC 2 单元测试阶段错误

Posted

技术标签:

【中文标题】ASP.NET MVC 2 单元测试阶段错误【英文标题】:ASP.NET MVC 2 Unit Testing Stange Errors 【发布时间】:2010-08-17 06:55:46 【问题描述】:

我正在阅读 Professional ASP.NET MVC 2 这本书,并且我正在尝试让第 1 章中的单元测试正常工作;但是,我遇到了一些非常奇怪的错误。

解决方案中有两个项目:NerdDinner 和 NerdDinner.Tests。

在 NerdDinner 项目中我有以下界面:

IDinnerRepository.cs

//...
namespace NerdDinner.Models

     interface IDinnerRepository
     
     //...
     

同样在 NerdDinner 项目中,我有以下类:

//...
using NerdDinner.Models;
//...
namespace NerdDinner.Controllers

     public class DinnersController : Controller
     
     IDinnerRepository dinnerRepository;
     // Default constructor
     public DinnersController() : this(new DinnerRepository()) // DinnerRepository is another concrete implementation of IDinnerRepository
     //Test constructor
     public DinnersController(IDinnerRepository repository) 
     dinnerRepository = repository;
     
     

在 NerdDinner.Tests 项目中,我有以下 IDinnerRepository 的具体实现:

//...
using NerdDinner.Models;
//...
namespace NerdDinner.Tests.Fakes

     class FakeDinnerRepository : IDinnerRepository
     
     //...
          public FakeDinnerRepository(List<Dinner> dinners)
          
          //...
          
     //...
     

现在进行实际的单元测试(在 NerdDinner.Tests 中)

using NerdDinner.Controllers;
//...
using NerdDinner.Models;
using NerdDinner.Tests.Fakes;
namespace NerdDinner.Tests

     [TestClass]
     public class DinnersControllerTest
     
          List<Dinner> CreateTestDinners()
          
          //...
          
          DinnersController CreateDinnersController()
          
          return new DinnersController(new FakeDinnerRepository(CreateTestDinners()));
          
     

现在针对实际问题: 在 DinnerControllerClass 类的 CreateDinnersController 方法中,出现以下错误:

DinnersController.DinnersController(NerdDinner.Models.IDinnerRepository 存储库)(+ 1 个重载) 错误: 'NerdDinner.Controllers.DinnersController.DinnersController(NerdDinner.Models.IDinnerRepository)' 的最佳重载方法匹配有一些无效参数。

它让我可以选择在 DinnersController 中创建构造函数存根。它生成以下代码:

private global::NerdDinner.Tests.Fakes.FakeDinnerRepository repository;
//...
public DinnersController(global::NerdDinner.Tests.Fakes.FakeDinnerRepository repository)

     // TODO: Complete member initialization
     this.repository = repository;

即使在生成该代码之后,我仍然会遇到同样的错误。但是为什么我还需要那个代码呢?据我所知,我做的一切都是正确的。

谁能帮我弄清楚这里发生了什么?

编辑 生成的代码给出以下错误:

命名空间“NerdDinner”中不存在类型或命名空间“Tests”(您是否缺少任何程序集引用?)

【问题讨论】:

【参考方案1】:

从您所显示的情况来看,IDinnerRepository 界面是公开的,这意味着它在您的单元测试中不可见。我建议您将其公开,因为我怀疑您有两种不同的接口:一种在单元测试中定义,另一种在您的项目中定义,但存在冲突。另外,我建议您避免依赖 Visual Studio 生成所有垃圾反射代码来测试私有和内部成员。

【讨论】:

我公开了界面,但我仍然遇到同样的错误。更正:错误不再存在。谢谢! @KPthunder:如果该接口以前不公开,您是如何设法在您的测试项目中实现它的?这就是为什么我建议检查“去定义”会带你去哪里...... @Jon Skeet:我刚刚输入了代码,它就起作用了。在我输入接口名称后,IDE 正在为我输入方法。我目前没有在这台计算机上安装 resharper,你认为 resharper 会发现这个吗? @KPthunder:我不确定,但您应该注意 IDE 正在为您做什么 - 接口必须以某种方式进入测试项目,并且你应该对此非常警惕。 @Jon Skeet:我不认为该界面在测试项目中,因为当我在未公开时按 F12 时,它会将我带到非测试项目中的界面。 【参考方案2】:

您遇到的最后一个错误是由于没有从生产代码引用到测试代码 - 但这是适当的。你不想要那个额外的构造函数。

相反,您需要找出为什么没有使用采用IDinnerRepository 的现有构造函数。你确定你只有一个叫IDinnerRepository的接口吗?如果你去FakeDinnerRepository源,去声明,把光标放在IDinnerRepository然后按F12(去定义)它去正确的地方吗?

如果您向IDinnerRepository 添加一个新成员(只是为了测试:void Foo(); 可以)是否会导致生产和假实现都无法编译?

【讨论】:

是的,F12 将我带到了 NerdDinner.Models 中的一个 IDinnerRepository。当我添加 void foo() 时,它迫使我将所有该方法应用于所有具体实现。

以上是关于ASP.NET MVC 2 单元测试阶段错误的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET-MVC:数据库默认值会破坏单元测试的精神吗? [关闭]

如何对 Asp.net MVC 文件进行单元测试

MVC 自定义过滤器,手动调用 ASP.NET 管道事件进行单元测试

在 ASP.NET Core MVC API 控制器上对 AuthorizeAttribute 进行单元测试

在 ASP.NET MVC 3 中的多个服务之间共享一个工作单元

UrlHelper 类在 Asp.net mvc 中引发空异常