Moq.Setup类型'System.Web.Mvc.ActionResult'的表达式不能用于返回类型'System.Web.Mvc.ActionResult'

时间:2016-08-04 19:54:18

标签: c# unit-testing moq mstest legacy-code

我正在研究一些遗留代码(def:未经测试的代码 - 有些设计得不好),并尝试开发一些测试以确认最近的更改是否达到了预期等等。我遇到了一个问题我在哪里试图强制一个在其中有try {catch}块的方法使用Moq抛出异常。当我尝试运行测试时,它在使用System.ArgumentException的mock.Setup调用期间失败“类型'System.Web.Mvc.ActionResult'的表达式不能用于返回类型'System.Web.Mvc.ActionResult'”。< / p>

代码的基本设置:

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块返回的内容。

编辑:通过建议对帖子进行了重大更新,以便更容易理解问题所在。

1 个答案:

答案 0 :(得分:1)

这是一个精简的例子

给出

public interface IServiceFactory {
    object GetService(string args);
}

public class MyController : Controller {
    IServiceFactory serviceFactory

    public MyController(IServiceFactory serviceFactory) {
        this.serviceFactory = serviceFactory;
    }

     // method under test
    public ActionResult DeleteFilter(string args) {
        try {
            var model = serviceFactory.GetService(args);
            return View(model);
        } catch(Exception ex) {
           return JsonActionResult(JsonReturnType.Error, ajaxMessage: "There was an error in deleting the filter.");
        }
    }         
}

您可以像测试一样在测试中使用moq

[TestMethod]
public void DeleteFilter_ExceptionThrown_IsCaughtAndLoggedAndReturnsActionResultOfError() {
    // Arrange
    var serviceFactoryMock = new Mock<IServiceFactory>();
    serviceFactoryMock
        .Setup(x => x.GetService(It.IsAny<string>())
        .Throws(new Exception())
        .Verifiable();

    var controller = new MyController(serviceFactoryMock.Object);

    // Act
    var result = controller.DeleteFilter("blah blah");

    //Assert
    serviceFactoryMock.Verify(); // verifies that the setup was invoked
    Assert.IsNotNull(result);
    Assert.IsInstanceOfType(result, typeof(JsonActionResult));
    //...other assertions
}

所以现在在调用DeleteFilter的示例中,调用模拟服务工厂,根据设置抛出错误,您可以断言从catch块返回的内容。