【发布时间】:2016-08-04 19:54:17
【问题描述】:
我正在处理一些遗留代码(定义:未经测试的代码 - 有些设计得很好有些没有)并尝试开发一些测试来确认最近的更改是否符合他们的预期等。我遇到了一个问题试图强制其中包含 try{catch} 块的方法使用 Moq 引发异常。当我尝试运行测试时,它在 mock.Setup 调用期间失败,System.ArgumentException“'System.Web.Mvc.ActionResult' 类型的表达式不能用于返回类型'System.Web.Mvc.ActionResult'”。
代码的基本设置:
FilterController 的接口...
public interface IFilterController
{
ActionResult DeleteFilter(string reportFilter, bool customReport = true);
}
FilterController 类...
public class FilterController : BaseController, IFilterController
{
public FilterController(
IServiceFactory serviceFactory,
IAwsServiceFactory awsServiceFactory,
IReportServiceFactory reportServiceFactory,
IAzureServiceFactory azureServiceFactory)
: base(typeof(FilterController), serviceFactory, awsServiceFactory, reportServiceFactory, azureServiceFactory)
{
}
// method under test
public ActionResult (string reportFilter, bool customReport = true) {
try {
// NOTE: I have trimmed down the actual code in the try block significantly for brevity - I should be able to hook onto something here as a way to mock something throwing an exception
var customReportFilterService = _serviceFactory.CreateCustomReportFilterService();
var emailReportSettingService = _serviceFactory.CreateEmailReportSettingService();
string message = string.Empty;
JsonReturnType type = JsonReturnType.DisplayMessage; // an enum
var filter = customReportFilterService.GetReportFilterByHash(SessionHelper.User.CustomerId, reportFilter, initLinkedProjects: true);
return JsonActionResult(type, ajaxMessage: message, redirectTo: filter == null ? null : string.Format("Report/{0}", filter.ReportName));
}
catch (Exception ex)
{
return JsonActionResult(JsonReturnType.Error, ajaxMessage: "There was an error in deleting the filter.");
}
}
}
BaseController 类...
public class BaseController : Controller
{
private readonly ProgressController _progressController;
protected IServiceFactory _serviceFactory;
protected IAwsServiceFactory _awsServiceFactory;
protected IReportServiceFactory _reportServiceFactory;
protected IAzureServiceFactory _azureServiceFactory;
protected IApplicationSettingService _applicationSettingService;
protected IReportMonitorService _reportMonitorService;
protected ISymmetricAlgorithmProvider HiddenEncrypter { get; set; }
private Stopwatch _watch;
private bool _timePageEnabled;
private bool _maintenance;
private int _pageLoadThreshold;
private readonly ILog Logger;
public BaseController(Type type, IServiceFactory serviceFactory, IAwsServiceFactory awsServiceFactory, IReportServiceFactory reportServiceFactory, IAzureServiceFactory azureServiceFactory)
{
Logger = LogManager.GetLogger(type);
_progressController = new ProgressController();
_serviceFactory = serviceFactory;
_awsServiceFactory = awsServiceFactory;
_reportServiceFactory = reportServiceFactory;
_azureServiceFactory = azureServiceFactory;
_applicationSettingService = _serviceFactory.CreateApplicationSettingService();
_reportMonitorService = _serviceFactory.CreateReportMonitorService();
_watch = new Stopwatch();
_timePageEnabled = _applicationSettingService.ReadApplicationSettingFromCache<bool>(CC.Data.Model.Constants.ApplicationSettings.CheckSlowPageLoad, true);
_pageLoadThreshold = _applicationSettingService.ReadApplicationSettingFromCache<int>(CC.Data.Model.Constants.ApplicationSettings.PageLoadThreshold, 120);
_maintenance = _applicationSettingService.MaintenanceMode();
}
// System.Web.Mvc.ActionResult type mentioned in error
public ActionResult JsonActionResult(JsonReturnType returnType, string view = null, string ajaxMessage = null, string redirectTo = null, string target = null, object data = null, string popupTitle = null)
{
if (returnType == JsonReturnType.LoadContent)
_progressController.CompleteProgressCache();
var serializer = new JavaScriptSerializer();
serializer.MaxJsonLength = Int32.MaxValue;
var resultData = new {
ReturnType = returnType,
HtmlView = view,
Message = ajaxMessage,
RedirectTo = redirectTo,
Target = target,
CustomData = data,
ProjectId = SessionHelper.ProjectId,
PopupTitle = popupTitle,
MaintenanceMode = _maintenance
};
ContentResult result;
result = new ContentResult
{
Content = serializer.Serialize(resultData),
ContentType = "application/json"
};
return result;
}
}
控制器类...
public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter {
// stuff
}
单元测试类...
[TestClass]
public class FilterControllerTest
{
private FilterController filterController;
private Mock<IFilterController> filterControllerMock;
private Mock<IServiceFactory> serviceFactoryMock;
private Mock<IAwsServiceFactory> awsServiceFactoryMock;
private Mock<IReportServiceFactory> reportServiceFactoryMock;
private Mock<IAzureServiceFactory> azureServiceFactoryMock;
private Mock<IApplicationSettingService> applicationSettingServiceMock;
[ClassInitialize]
public static void ClassInit(TestContext context)
{
}
[TestInitialize]
public void Initialize()
{
filterControllerMock = new Mock<IFilterController>();
serviceFactoryMock = new Mock<IServiceFactory>();
awsServiceFactoryMock = new Mock<IAwsServiceFactory>();
reportServiceFactoryMock = new Mock<IReportServiceFactory>();
azureServiceFactoryMock = new Mock<IAzureServiceFactory>();
applicationSettingServiceMock = new Mock<IApplicationSettingService>();
serviceFactoryMock
.Setup(s => s.CreateApplicationSettingService())
.Returns(applicationSettingServiceMock.Object);
filterController = new FilterController(
serviceFactoryMock.Object
, awsServiceFactoryMock.Object
, reportServiceFactoryMock.Object
, azureServiceFactoryMock.Object);
}
[TestCleanup]
public void Cleanup()
{
}
[ExpectedException(typeof(Exception))]
[TestMethod]
public void DeleteFilter_ExceptionThrown_IsCaughtAndLoggedAndReturnsActionResultOfError()
{
// Arrange
filterControllerMock
.Setup(x => x.DeleteFilter(It.IsAny<string>(), It.IsAny<bool>()))
.Throws(new Exception());
// Act
var result = filterController.DeleteFilter("myfilt", false);
}
}
最后我想做的就是拥有它,所以当为此测试调用 DeleteFilter 时,会引发错误,然后我可以断言从 catch 块返回的内容。
编辑:根据建议对帖子进行了重大更新,以便更容易理解问题所在。
【问题讨论】:
-
根据示例
IFilterController接口没有定义TestMethod方法。它只定义了DeleteFilter -
请提供minimal reproducible example 您的问题和预期行为。
-
不,这不是它的做法。显示测试初始化代码。您通常希望模拟被测系统的依赖关系。到目前为止,您展示的示例没有明显的依赖关系
-
根据您更新的示例,
filterController和filterControllerMock在单元测试的 ocntext 中没有任何关系。是否使用示例//stuff的 try 部分执行的任何依赖项。它是您需要设置模拟异常的地方。你甚至不需要在这个测试中模拟IFilterController -
现在做一个例子
标签: c# unit-testing moq mstest legacy-code