How do I check if a view's model is correct? - unit-testing

I have an "Index" controller method which returns a view with a Model that is a List<WhatsNew>. I am trying to validate this method in a unit test but it gives me an error as it is expecting a string.
Controller
public ActionResult Index()
{
return View("Index", GetWhatsNew());
}
public List<WhatsNew> GetWhatsNew()
{
WCMSDataContext wcmsContext = new WCMSDataContext();
return (from p in wcmsContext.WhatsNews select p).ToList();
}
Unit Test
[TestMethod]
public void Validate_Index_IList_WhatsNew_AS_Model()
{
AppItemController controller = new AppItemController();
// Act
var result = controller.Index();
// Assert
var model = ((ViewResult)result).Model as List<WhatsNew>;
Assert.AreEqual("Index", model.ToList());
}
Error
Assert.AreEqual failed. Expected:<Index (System.String)>. Actual: <System.Collections.Generic.List`1[WCMS.WhatsNew]

You're comparing a string "Index" with a List<WhatsNew>:
Assert.AreEqual("Index", model.ToList());
What exactly are you expecting to happen here?
You can check the contents of the model:
Assert.AreEqual(someValue, model.Count);
Assert.AreEqual(someOtherValue, model[0].SomeProperty);
You can also check the right page is being returned in the action:
Assert.AreEqual("Index", ((ViewResult)result).ViewName);
At the moment, you seem to be trying to mix the two...
You may want to have a read of something like this as a basic introduction to checking your controllers.

Related

how to assert values from anonymous type passed from an oknegatiatedresult

I'm currently unit testing controllers, and my controller code goes like this
public IHttpActionResult Submit(){
...
return Ok(new { Success = true, ErrorMessage = "", RedirectUrl = "http://myurl" });
}
in my unit test method goes like this
var result = sut.Submit(); //result is not null
result is not null however I can't get any of the anonymous properties sent by the method I called. no other properties like "value" or "content" available from VS intelisense. any idea how to get those values so I can assert them further?

Unit Test NService.Send from an API Controller

I have an API Controller which publishes a command using NServiceBus. I am using NUnit and NSubstitute for testing. I want to test that certain properties from the model are populated on the command
Here is my controller with a route.
[RoutePrefix("api/fileService")]
public class FileServiceController : ApiController
{
[HttpPost]
[Route("releasefile")]
public async Task<IHttpActionResult> ReleaseFile(FileReleaseAPIModels.ReleaseFileModel model)
{
var currentUser = RequestContext.Principal?.Identity as ClaimsIdentity;
if (model.FileType.Equals("ProductFile"))
{
_logger.Info($"Releasing Product files for date: {model.FileDate.ToShortDateString()} ");
_bus.Send<IReleaseProductFiles>("FileManager.Service", t =>
{
t.FileId = Guid.NewGuid();
t.RequestedDataDate = model.FileDate;
t.RequestingUser = currentUser?.Name;
t.RequestDateTime = DateTime.Now;
});
}
return Ok();
}
}
In my test, I substitute(mock) Ibus and try to validate the call received. Here is the test method:
[Test]
public async Task TestReleaseProductsFile()
{
var bus = Substitute.For<IBus>();
var dbContent = _container.Resolve<IFileManagerDbContext>();
var apiContext = new FileServiceController(bus, dbContent);
//Create a snapshot
var releaseDate = DateTime.Now.Date;
var result = await apiContext.ReleaseFile(new ReleaseFileModel
{
FileDate = releaseDate,
FileType = "ProductFile"
});
Assert.That(result, Is.Not.Null, "Result is null");
Assert.That(result, Is.TypeOf<OkResult>(), "Status code is not ok");
bus.Received(1)
.Send<IReleaseProductFiles>(Arg.Is<string>("FileManager.Service"), Arg.Is<Action<IReleaseProductFiles>>(
action =>
{
action.FileId = Guid.NewGuid();
action.RequestedDataDate = releaseDate;
action.RequestingUser = String.Empty;
action.RequestDateTime = DateTime.Now;
}));
}
This results in error - even though the message is actually sent. Here is the error message:
NSubstitute.Exceptions.ReceivedCallsException : Expected to receive exactly 1 call matching:
Send<IReleaseProductFiles>("Capelogic.Service", Action<IReleaseProductFiles>)
Actually received no matching calls.
Received 1 non-matching call (non-matching arguments indicated with '*' characters):
Send<IReleaseProductFiles>("Capelogic.Service", *Action<IReleaseProductFiles>*)
I am obviously missing something obvious here.
The problem here is with the Action<IReleaseProductFiles> argument to Send -- we can't automatically tell if two different actions are the same. Instead, NSubstitute relies on the references being equivalent. Because both the test and the production code create their own Action instance, these will always be different and NSubstitute will say the calls don't match.
There are a few different options for testing this. These examples relate to Expression<Func<>>, but the same ideas apply to Action<>s.
In this case I'd be tempted to test this indirectly:
[Test]
public async Task TestReleaseProductsFile()
{
var bus = Substitute.For<IBus>();
var returnedProductFiles = Substitute.For<IReleaseProductFiles>();
// Whenever bus.Send is called with "FileManager.Service" arg, invoke
// the given callback with the `returnedProductFiles` object.
// We can then make sure the action updates that object as expected.
bus.Send<IReleaseProductFiles>(
"FileManager.Service",
Arg.Invoke<IReleaseProductFiles>(returnedProductFiles));
// ... remainder of test ...
Assert.That(result, Is.TypeOf<OkResult>(), "Status code is not ok");
Assert.That(returnedProductFiles.FileId, Is.Not.EqualTo(Guid.Empty));
Assert.That(returnedProductFiles.RequestedDataDate, Is.EqualTo(releaseDate));
Assert.That(returnedProductFiles.RequestingUser, Is.EqualTo(String.Empty));
}
I'd recommend having a look through the previously mentioned answer though to see if there is a better fit for your situation.

How can i write unit test for this actionfilter

public MyContext _db;
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (_db == null || !_db.ChangeTracker.HasChanges())
{
return;
}
try
{
_db.SaveChanges();
}
catch
{
}
}
This is my action filter for my wep api project. _db context object injected to this filter by per request. My point is here to call SaveChanges() method once after all processing done in service layers. My problem is how can test this filter? How can i mimic exception case that can happen in any controler or service layer and when exception throws saveChanges() never called? How can i setup the case that exception occurred in any place inside application?
I have been doing the same, last week, for my WebAPI 2 action filter.
I have an action filter that validates my ModelState and in case of any error it throws an error list with 200 HTTPcode.
The action looks like this:
public class ModelValidationActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var modelState = actionContext.ModelState;
if (!modelState.IsValid)
{
actionContext.Response = ...
}
}
}
UNIT TEST
var httpControllerContext = new HttpControllerContext
{
Request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/someUri")
{
Content = new ObjectContent(typeof(MyModel),
new MyModel(), new JsonMediaTypeFormatter())
},
RequestContext = new HttpRequestContext()
};
httpControllerContext.Request = new HttpRequestMessage();
httpControllerContext.Request.SetConfiguration(new HttpConfiguration());
var httpActionContext = new HttpActionContext { ControllerContext = httpControllerContext };
var filter = new ModelValidationActionFilterAttribute();
httpActionContext.ModelState.AddModelError("*", "Invalid model state");
// act
filter.OnActionExecuting(httpActionContext);
// assert
httpActionContext.Response.ShouldNotBe(null);
httpActionContext.Response.ShouldBeOfType(typeof (HttpResponseMessage));
var result = httpActionContext.Response.Content.ReadAsStringAsync().Result;
BaseServiceResponse<object> resultResponse =
JsonConvert.DeserializeObject<BaseServiceResponse<object>>(result);
resultResponse.Data.ShouldBe(null);
resultResponse.Messages.Count.ShouldBe(1);
resultResponse.Messages.First().Description.ShouldBe("Invalid model state");
In your case you need to Mock DB context using IDbContext interface - see here: http://aikmeng.com/post/62817541825/how-to-mock-dbcontext-and-dbset-with-moq-for-unit
If an unhandled exception occurs while executing the request then the Exception property on actionExecutedContext will contain the exception. This is part of the framework, and not something you need to test. In your tests you can simple set the Exception property manually and assert that the attribute takes the correct action.
[Fact]
public void Saves_data_on_failure()
{
var mockDbContext = new Mock<IDbContext>();
var myAttribute = new MyAttribute(mockDbContext.Object);
var executionContext = new HttpActionExecutedContext
{
Exception = new Exception("Request failed.")
};
myAttribute.OnActionExecuted(executionContext);
mockDbContext.Verify(d => d.SaveChanges());
}
You might also want to consider whether or not you want to save data for all types of exception. The data might be in an invalid/unknown state.

Asp. NET MVC 4.5 - How to Unit Test Actions?

In Asp.net MVC 4.5 , using Microsoft.VisualStudio.TestTools.UnitTesting.
is there a way to really unit test an ActionResult? All documentation I have seen only tests the view name!
Assert.AreEqual("Action Method", result.ViewName);
Well, I want to have a really test. How can I test the response of the controller-action ?
Given something basic along the lines of:
public ActionResult Display(string productCode)
{
var model = new ProductModel(productCode);
if (model.NotFound)
{
return this.RedirectToRoute("NotFound");
}
return this.View("Product", model);
}
Instead of something that asserts like Assert.AreEqual("Action Method", result.ViewName); (which can be a valid test.
You have many options including...
Looking at the model type
[TestMethod]
public void Display_WhenPassedValidProductCode_CreatesModel()
{
using (var controller = this.CreateController())
{
// Arrange Mocks on controller, e.g. a Service or Repository
// Act
var result = controller.Display(string.Empty) as ViewResult;
var model = (ProductModel)result.Model;
Assert.IsInstanceOfType(model, typeof(ProductModel));
}
}
Looking at the model population process
[TestMethod]
public void Display_WhenPassedValidProductCode_PopulatesModel()
{
using (var controller = this.CreateController())
{
const string ProductCode = "123465";
// Arrange Mocks on controller, e.g. a Service or Repository
// Act
var result = controller.Display(ProductCode) as ViewResult;
var model = (ProductModel)result.Model;
Assert.AreEqual(ProductCode, model.ProductCode);
}
}
Looking at the type of action result
[TestMethod]
public void Display_WhenNotFound_Redirects()
{
using (var controller = this.CreateController())
{
const string ProductCode = "789000";
// Arrange Mocks on controller, e.g. a Service or Repository
// Act
var result = controller.Display(ProductCode) as RedirectToRouteResult;
Assert.IsNotNull(result); // An "as" cast will be null if the type does not match
}
}
Basically you can test pretty much anything, pick an example on your code base and try and test it. If you get stuck construct a decent question and post it here.

MVC4 - TryValidateModel breaks unit tests

I have the following controller method
public ActionResult Create(Category category)
{
//default values
if (string.IsNullOrEmpty(category.GeoAreaLevelIdentifier))
{
category.GeoAreaLevelIdentifier = "OutputArea";
}
category.CreatorIdentifier = EsdContext.User.UniqueIdentifier.ToString();
category.Created = DateTime.Now;
//validation
RevalidateModel(category);
new CategoryBroker().Create(category);
return JsonNow(category);
}
which fills some default values to the model and THEN validates it. This is because the client code is allowed to submit a model without some of the required fields. The missing fields are filled by the controller (see above).
RevalidateModel method calls TryValidateModel:
protected void RevalidateModel(object model)
{
ModelState.Clear();
TryValidateModel(model); //called explicitly since model has been updated
if (!ModelState.IsValid)
{
//error message
}
}
But when I call Create method from a unit test, it fails because TryValidateModel expects controllerContext:
Value cannot be null.Parameter name: controllerContext
What is the best way to solve this problem?
Should I create the controllerContext eg by MvcContrib TestHelper?
In this case
using Moq;
.........
readonly MockRepository _mockRepository = new MockRepository(MockBehavior.Default);
.........
controller.ControllerContext = _mockRepository.Create<ControllerContext>().Object;
works good enough.
Best.