I am writing a similar testing framework like this one: https://github.com/ivaylokenov/MyTested.WebApi but for ASP.NET 5 MVC 6 (using 6.0.0-beta8).
I have a hard time trying to invoke the controller's TryValidateModel to validate the ModelState of a given object. It worked without any pain on ASP.NET Web API 2 controller. Which properties should I instantiate on the controller class in order for the method to validate with the default conventions. I receive either null reference exception or valid model state no matter the model and the property attributes.
I've been searching in the MVC source code for a couple of hours with no luck. I have tried to set the AddMvc() services on the controller - not working for me. I even tried their testing controller type located HERE (the GetController private method) but with no luck. Here is the source I am currently using:
// TODO: for real this is how we configure controller?
var detailsProviders = new IMetadataDetailsProvider[]
{
new DefaultBindingMetadataProvider(new ModelBindingMessageProvider
{
MissingBindRequiredValueAccessor = name => $"A value for the '{ name }' property was not provided.",
MissingKeyOrValueAccessor = () => $"A value is required.",
ValueMustNotBeNullAccessor = value => $"The value '{ value }' is invalid.",
}),
new DefaultValidationMetadataProvider(),
new DataAnnotationsMetadataProvider(),
// new DataMemberRequiredBindingMetadataProvider(), TODO: not available in version 8 but it is in the source code of MVC
};
var compositeDetailsProvider = new DefaultCompositeMetadataDetailsProvider(detailsProviders);
var metadataProvider = new DefaultModelMetadataProvider(compositeDetailsProvider);
var httpContext = new DefaultHttpContext();
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
var viewData = new ViewDataDictionary(metadataProvider, new ModelStateDictionary());
var tempData = new TempDataDictionary(new HttpContextAccessor(), new SessionStateTempDataProvider());
var bindingContext = new ActionBindingContext()
{
ModelBinder = new GenericModelBinder(),
ValueProvider = new CompositeValueProvider(new IValueProvider[0]),
InputFormatters = new List<IInputFormatter>(),
ValidatorProvider = new DataAnnotationsModelValidatorProvider(
options: null,
stringLocalizerFactory: null)
};
this.Controller.ActionContext = actionContext;
this.Controller.BindingContext = bindingContext;
this.Controller.MetadataProvider = metadataProvider;
this.Controller.ViewData = viewData;
this.Controller.TempData = tempData;
this.Controller.ObjectValidator = new DefaultObjectValidator(new IExcludeTypeValidationFilter[0], metadataProvider);
Any help will be appreciated. Thank you in advance!
Turns out it is actually a bug in ASP.NET MVC and the team will fix it for the next RC2 version: https://github.com/aspnet/Mvc/issues/3586
Related
I'm currently working on a POC MDS/MDM WCF service and have a question regarding validation. Does anyone have an example of calling the MDS web api to kick of validating the MDS model? I know i have to add a service reference to MDS in order to gain access to the proxies, i was just hoping for a simple example of using the api.
https://msdn.microsoft.com/en-us/library/microsoft.masterdataservices.serviceclient.validationprocess(v=sql.110).aspx
//ValidationProcess For an entity
public Collection<ValidationIssue> ValidationProcess(string ModelName, string verName, string EntityName, string memCode)
{
//Instantiate all of request and response objects
ValidationProcessRequest Request = new ValidationProcessRequest();
ValidationProcessResponse Response = new ValidationProcessResponse();
//Instantiate the Criteria and Options objects
Request.ValidationProcessCriteria = new ValidationProcessCriteria();
Request.ValidationProcessOptions = new ValidationProcessOptions();
//Set Model and Version Identifiers - these will be required in all instances
Request.ValidationProcessCriteria.ModelId = new Identifier { Name = ModelName };
Request.ValidationProcessCriteria.VersionId = new Identifier { Name = verName };
Request.ValidationProcessCriteria.EntityId = new Identifier { Name = EntityName };
Request.ValidationProcessCriteria.Members = new Collection<MemberIdentifier>();
Request.ValidationProcessCriteria.Members.Add(new MemberIdentifier { Code = memCode });
//Options can return validation results or trigger the commit of a version (when validation is already successful)
Request.ValidationProcessOptions.ReturnValidationResults = true;
Response = mds_Proxy.ValidationProcess(Request);
return Response.ValidationIssueList;
}
I have tried following code in ASP.NET MVC
DBEntities dbEntity = new DBEntities();
StudentModel stdsearch = new StudentModel();
var students = (from std in dbEntity.STUDENT
select std).ToList();// Returns around 400 rows
// Tried following code for json error
var jsonResult = Json(students, JsonRequestBehavior.AllowGet);
jsonResult.MaxJsonLength = int.MaxValue;
return jsonResult;
Now i am getting out of memory exception
I have also cleared temp data.Also tried the following code
var serializer = new JavaScriptSerializer { MaxJsonLength = Int32.MaxValue, RecursionLimit = 100 };
return new ContentResult()
{
Content = serializer.Serialize(students),
ContentType = "application/json",
};
Remove the circular reference.
If you want to convert "STUDENT" model alone not an other reference model.
Set LazyLoading true to DBContext
Ex:
context.Configuration.LazyLoadingEnabled = true;
Try to run your application as 64 bit. If it is 32 bit then you will have low memory.
I am trying to Mock a HttpResponse for a ConrollerContext object using MVC 4, Moq 4 and C# 4.5
My code is here:
var context = new Mock<HttpContextBase>();
var response = new Mock<HttpResponseBase>();
context.SetupProperty(c => c.Response = response);
I have tried using Setup().Returns() and SetupGet() but I keep getting the following error:
"Property or Indexer 'System.Web.HttpContextBase.Response' cannot be assigned to -- it is read only.
I have tried Googling this and searching on this website, but I can't seem to find the answer.
For get-only properties, use SetupGet(..), and specify a .Returns(..) clause with the return value to inject:
var context = new Mock<HttpContextBase>();
var response = new Mock<HttpResponseBase>();
context.SetupGet(c => c.Response)
.Returns(response.Object);
It seems that I did not pass the correct object into the Returns() method. I should have passed the mock's Object property.
Here is the correct code:
var context = new Mock<HttpContextBase>();
var response = new Mock<HttpResponseBase>();
context.Setup(c => c.Response).Returns(response.Object);
I'm creating a really simple ViewResult subclass called JavaScriptViewResult that, when executing, calls the base implementation and then sets the Content-Type of the response to text/javascript. In trying to unit test this class, I'm running across a slew of difficulties fulfilling all of the dependencies of the ASP.NET MVC stack.
Here is what my unit test, which uses Rhino, looks like so far:
[TestMethod]
public void TestExecuteAction()
{
var request = MockRepository.GenerateMock<HttpRequestBase>();
request.Expect(m => m.Url).Return(new Uri("/Test/JavaScript", UriKind.Relative));
var httpContext = MockRepository.GenerateMock<HttpContextBase>();
httpContext.Expect(m => m.Request).Return(request);
var controller = MockRepository.GenerateMock<ControllerBase>();
var virtualPathProvider = MockRepository.GenerateMock<VirtualPathProvider>();
var routeCollection = new RouteCollection(virtualPathProvider);
routeCollection.MapRoute("FakeRoute", "Test/JavaScript", new { controller = "Test", action = "JavaScript" });
var routeData = routeCollection.GetRouteData(httpContext);
var context = new ControllerContext(httpContext, routeData, controller);
var viewResult = new JavaScriptViewResult();
viewResult.ExecuteResult(context);
Assert.AreEqual("text/javascript", context.HttpContext.Response.ContentType);
}
The latest exception when running the test is a NullReferenceException deep within the bowels of System.Web.Routing.Route.GetRouteData(HttpContextBase httpContext).
How do I set up all of the dependencies for executing a ViewResult? Are there any techniques for making this simpler? Alternately, is there a different way I can utilize the MVC view engine to generate JavaScript that will set the proper Content-Type for the response?
I figured out how to meet the minimum requirements of ViewResult. One problem I was encountering was mocking the process of finding the view. This was avoidable by ensuring that the View property of my object was populated. Here is my working test:
[TestMethod]
public void TestExecuteAction()
{
var response = MockRepository.GenerateStub<HttpResponseBase>();
response.Output = new StringWriter();
var httpContext = MockRepository.GenerateMock<HttpContextBase>();
httpContext.Expect(m => m.Response).Return(response);
var routeData = new RouteData();
routeData.Values.Add("action", "FakeAction");
var context = new ControllerContext(httpContext, routeData, MockRepository.GenerateMock<ControllerBase>());
var viewResult = new JavaScriptViewResult();
viewResult.View = MockRepository.GenerateMock<IView>();
viewResult.ExecuteResult(context);
Assert.AreEqual("text/javascript", context.HttpContext.Response.ContentType);
}
As suggested by (among others) Kazi Manzur Rashid in this blog post, I am using ActionFilterAttributes to transfer model state from one request to another when redirecting.
However, I find myself unable to write a unit test that test the behavior of these attributes. As an example, this what I want the test for the ImportModelStateAttribute to do:
Setup the filterContext so that TempData[myKey] contains some fake "exported" ModelState (that is, a ModelStateDictionary I create myself, and add one error to)
Make ModelState contain one model error.
Call OnActionExecuting.
Verify the two dictionaries are merged, and ModelState now contains both errors.
I'm at a loss already on the first step.
EDIT:
Yes, I've tried mocking ActionFilterAttribute with Moq, but I get errors stating
Invalid setup on non-overridable member
for both TempData and ModelState.
Tomas, You do not have to mock the filterContext, you can create the real object for testing the action filter, the same goes for the model state, these are poco objects. Only thing that you have to mock is the HttpContext (if needed).
[Fact]
public void Should_import_complete_view_data()
{
var attribute = new ImportViewDataFromTempDataAttribute();
var httpContext = new Mock<HttpContextBase>();
var requestContext = new RequestContext(httpContext.Object, new RouteData());
var previousModel = new object();
var previousViewData = new ViewDataDictionary(previousModel) {{"foo", "bar"}};
previousViewData.ModelState.AddModelError("foo", "bar");
var controller = new Mock<ControllerBase>();
controller.Object.ViewData = new ViewDataDictionary();
controller.Object.TempData = new TempDataDictionary { { attribute.Key, previousViewData } };
var controllerContext = new ControllerContext(requestContext, controller.Object);
var actionContext = new ActionExecutingContext(controllerContext, new Mock<ActionDescriptor>().Object, new Dictionary<string, object>());
attribute.OnActionExecuting(actionContext);
Assert.True(actionContext.Controller.ViewData.ContainsKey("foo"));
Assert.True(actionContext.Controller.ViewData.ModelState.ContainsKey("foo"));
Assert.Same(previousModel, actionContext.Controller.ViewData.Model);
}