From 57c04835de917aab3eb417292b0ecee2436d11dc Mon Sep 17 00:00:00 2001 From: Youngjune Hong Date: Tue, 3 Feb 2015 10:19:36 -0800 Subject: [PATCH] Updating ActionContext for the default constructor and the setter methods --- .../ActionContext.cs | 48 +++++++++-- src/Microsoft.AspNet.Mvc.Core/Controller.cs | 43 +++++++--- .../ControllerTests.cs | 2 +- .../ControllerUnitTestabilityTests.cs | 81 +++++++++++++++++++ 4 files changed, 156 insertions(+), 18 deletions(-) diff --git a/src/Microsoft.AspNet.Mvc.Core/ActionContext.cs b/src/Microsoft.AspNet.Mvc.Core/ActionContext.cs index b76135615c..c44b071fe1 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ActionContext.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ActionContext.cs @@ -12,6 +12,17 @@ namespace Microsoft.AspNet.Mvc /// public class ActionContext { + /// + /// Creates a empty . + /// + /// + /// The default constructor is provided for unit test purposes only. + /// + public ActionContext() + { + ModelState = new ModelStateDictionary(); + } + /// /// Creates a new . /// @@ -56,23 +67,44 @@ namespace Microsoft.AspNet.Mvc } /// - /// Gets the for the selected action. + /// Gets or sets the for the selected action. /// - public ActionDescriptor ActionDescriptor { get; } + /// + /// The property setter is provided for unit test purposes only. + /// + public ActionDescriptor ActionDescriptor + { + get; set; + } /// - /// Gets the for the current request. + /// Gets or sets the for the current request. /// - public HttpContext HttpContext { get; } + /// + /// The property setter is provided for unit test purposes only. + /// + public HttpContext HttpContext + { + get; set; + } /// /// Gets the . /// - public ModelStateDictionary ModelState { get; } + public ModelStateDictionary ModelState + { + get; + } /// - /// Gets the for the current request. + /// Gets or sets the for the current request. /// - public RouteData RouteData { get; } + /// + /// The property setter is provided for unit test purposes only. + /// + public RouteData RouteData + { + get; set; + } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/Controller.cs b/src/Microsoft.AspNet.Mvc.Core/Controller.cs index 3220131163..4350b2fb62 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Controller.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Controller.cs @@ -20,6 +20,7 @@ namespace Microsoft.AspNet.Mvc { private DynamicViewData _viewBag; private ViewDataDictionary _viewData; + private ActionContext _actionContext; public IServiceProvider Resolver { @@ -69,8 +70,32 @@ namespace Microsoft.AspNet.Mvc } } + /// + /// Gets or sets the object. + /// + /// + /// activates this property while activating controllers. If user codes + /// directly instantiate controllers, the getter returns an empty . + /// [Activate] - public ActionContext ActionContext { get; set; } + public ActionContext ActionContext + { + get + { + // This should run only for the controller unit test scenarios + _actionContext = _actionContext ?? new ActionContext(); + return _actionContext; + } + set + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + _actionContext = value; + } + } [Activate] public ActionBindingContext BindingContext { get; set; } @@ -822,7 +847,7 @@ namespace Microsoft.AspNet.Mvc } /// - /// Updates the specified instance using values from the controller's current + /// Updates the specified instance using values from the controller's current /// and a . /// /// The type of the model object. @@ -847,7 +872,7 @@ namespace Microsoft.AspNet.Mvc } /// - /// Updates the specified instance using the and a + /// Updates the specified instance using the and a /// . /// /// The type of the model object. @@ -882,14 +907,14 @@ namespace Microsoft.AspNet.Mvc } /// - /// Updates the specified instance using values from the controller's current + /// Updates the specified instance using values from the controller's current /// and a . /// /// The type of the model object. /// The model instance to update. /// The prefix to use when looking up values in the current . /// - /// (s) which represent top-level properties + /// (s) which represent top-level properties /// which need to be included for the current model. /// A that on completion returns true if the update is successful [NonAction] @@ -920,7 +945,7 @@ namespace Microsoft.AspNet.Mvc } /// - /// Updates the specified instance using values from the controller's current + /// Updates the specified instance using values from the controller's current /// and a . /// /// The type of the model object. @@ -957,7 +982,7 @@ namespace Microsoft.AspNet.Mvc } /// - /// Updates the specified instance using the and a + /// Updates the specified instance using the and a /// . /// /// The type of the model object. @@ -965,7 +990,7 @@ namespace Microsoft.AspNet.Mvc /// The prefix to use when looking up values in the /// /// The used for looking up values. - /// (s) which represent top-level properties + /// (s) which represent top-level properties /// which need to be included for the current model. /// A that on completion returns true if the update is successful [NonAction] @@ -997,7 +1022,7 @@ namespace Microsoft.AspNet.Mvc } /// - /// Updates the specified instance using the and a + /// Updates the specified instance using the and a /// . /// /// The type of the model object. diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs index 70145c2af7..88e8dbfd2e 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs @@ -1277,7 +1277,7 @@ namespace Microsoft.AspNet.Mvc.Test var binder = new Mock(); var controller = GetController(binder.Object, provider: null); controller.BindingContext.ValidatorProvider = provider.Object; - + // Act var result = controller.TryValidateModel(model, "Prefix"); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ControllerUnitTestabilityTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ControllerUnitTestabilityTests.cs index ad2aee496f..409045d2cf 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ControllerUnitTestabilityTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ControllerUnitTestabilityTests.cs @@ -5,7 +5,11 @@ using System; using System.Collections.Generic; using System.IO; using System.Text; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Mvc.ModelBinding; +using Microsoft.AspNet.Routing; using Microsoft.AspNet.WebUtilities; +using Moq; using Xunit; namespace Microsoft.AspNet.Mvc @@ -424,6 +428,83 @@ namespace Microsoft.AspNet.Mvc Assert.Throws(() => controller.Redirect_Action(null)); } + [Fact] + public void ControllerActionContext_ReturnsNotNull() + { + // Arrange && Act + var controller = new TestabilityController(); + + // Assert + Assert.NotNull(controller.ActionContext); + Assert.NotNull(controller.ActionContext.ModelState); + Assert.Null(controller.ActionContext.ActionDescriptor); + Assert.Null(controller.ActionContext.HttpContext); + Assert.Null(controller.ActionContext.RouteData); + } + + [Fact] + public void ActionContextDefaultConstructor_CanBeUsedForControllerActionContext() + { + // Arrange + var actionContext = new ActionContext(); + var controller = new TestabilityController(); + + // Act + controller.ActionContext = actionContext; + + // Assert + Assert.Equal(actionContext.HttpContext, controller.Context); + Assert.Equal(actionContext.RouteData, controller.RouteData); + Assert.Equal(actionContext.ModelState, controller.ModelState); + } + + [Fact] + public void ActionContextSetters_CanBeUsedWithControllerActionContext() + { + // Arrange + var actionDescriptor = new Mock(); + var httpContext = new Mock(); + var routeData = new Mock(); + + var actionContext = new ActionContext() + { + ActionDescriptor = actionDescriptor.Object, + HttpContext = httpContext.Object, + RouteData = routeData.Object, + }; + + var controller = new TestabilityController(); + + // Act + controller.ActionContext = actionContext; + + // Assert + Assert.Equal(httpContext.Object, controller.Context); + Assert.Equal(routeData.Object, controller.RouteData); + Assert.Equal(actionContext.ModelState, controller.ModelState); + Assert.Equal(actionDescriptor.Object, actionContext.ActionDescriptor); + } + + [Fact] + public void ActionContextModelState_ShouldBeSameAsViewDataAndControllerModelState() + { + // Arrange + var actionContext = new ActionContext(); + var controller1 = new Controller(); + var controller2 = new Controller(); + + // Act + controller2.ActionContext = actionContext; + + // Assert + Assert.Equal(controller1.ModelState, controller1.ActionContext.ModelState); + Assert.Equal(controller1.ModelState, controller1.ViewData.ModelState); + + Assert.Equal(actionContext.ModelState, controller2.ModelState); + Assert.Equal(actionContext.ModelState, controller2.ActionContext.ModelState); + Assert.Equal(actionContext.ModelState, controller2.ViewData.ModelState); + } + public static IEnumerable TestabilityViewTestData { get