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.
Related
I have a business class that manage a USER entity.
In this class I have a method to return a single user by id:
public Utente GetUser(int id)
{
var utente = _userDataManager.GetUserById(id);
return _mapper.Map<Utente>(utente);
}
_userDataManager is an interface, IUSERDATAMANAGER, and it has implemented with a DAL class; GetUserById return a user or null (search made with EF6).
_mapper is a IMAPPER interface (automapper).
The method return is the mapped object.
I have two question:
Does it make sense to test this method?
Should I mock both the object?
A black-boxed example will be appreciated.
Does it make sense to test this method?
If it is worth writing the code it is worth testing the code.
Should I mock both the object?
When testing a subject under test, you mock the dependencies that would allow the test to be exercised to completion.
For example
public void GetUser_Should_Return_Utente() {
//Arrange
var userId = 2;
var user = new User {
UserId = userId,
//... other properties
};
var userDataManagerMock = new Mock<IUserDataManager>();
userDataManagerMock.Setup(_ => _.GetUserById(userId)).Returns(user);
var expected = new Utente {
Id = user.Id,
//...other properties
}
var mapperMock = new Mock<IMapper>();
mapperMock.Setup(_ => _.Map<Utente>(It.IsAny<object>())).Returns(expected);
var subject = new MyBusinessClass(userDataManagerMock.Object, mapperMock.Object);
//Act
var actual = subject.GetUser(userId);
//Assert
Assert.Equal(expected, actual);
}
In the above code the user data manager and the mapper a mocked and injected into the subject when testing the GetUser method.
This is an isolated unit test of the above method and shows the the current implementation of that method will flow to completion provided the dependencies perform as expected during invocation.
I am developing an ASP.NET web API application. I am unit testing to every component in my application. I am using Moq Unit Test framework to mock the data. Now I am trying to mock the Configuration.Formatters.JsonFormatter in my Unit test because my action under unit test is using it as follows:
public HttpResponseMessage Register(model)
{
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.BadRequest,
Content = new ObjectContent<List<string>>(errors, Configuration.Formatters.JsonFormatter)
};
}
I am trying to mock the Configuration.Formatters.JsonFormatter in the Unit Test as follow.
[TestMethod]
public void Register_ReturnErrorsWithBadRequest_IfValidationFails()
{
PostUserRegistration model = new PostUserRegistration {
Name = "Wai Yan Hein",
Email = "waiyanhein#gmail.com",
Password = ""
};
Mock<JsonMediaTypeFormatter> formatterMock = new Mock<JsonMediaTypeFormatter>();
Mock<MediaTypeFormatterCollection> formatterCollection = new Mock<MediaTypeFormatterCollection>();
formatterCollection.Setup(x => x.JsonFormatter).Returns(formatterMock.Object);
Mock<HttpConfiguration> httpConfigMock = new Mock<HttpConfiguration>();
httpConfigMock.Setup(x => x.Formatters).Returns(formatterCollection.Object);
Mock<IAccountRepo> accRepoMock = new Mock<IAccountRepo>();
AccountsController controller = new AccountsController(accRepoMock.Object);
controller.Configuration = httpConfigMock.Object;
controller.ModelState.AddModelError("", "Faking some model error");
HttpResponseMessage response = controller.Register(model);
Assert.AreEqual(response.StatusCode, System.Net.HttpStatusCode.BadRequest);
}
When I run my unit tests, it is giving me this error.
System.NotSupportedException: Invalid setup on a non-virtual
(overridable in VB) member: x => x.JsonFormatter
So, how can I fix that error and how can I mock Configuration.Formatters.JsonFormatter?
You should not have to test that the framework is doing what it was designed to do. Instead, similar to what was suggested before in comments, I suggest using the built in methods of the ApiController and also refactoring the action to the syntax suggested from documentation for that version of Asp.Net Web API
public IHttpActionResult Register(PostUserRegistration model) {
if (!ModelState.IsValid)
return BadRequest(ModelState); //<-- will extract errors from model state
//...code removed for brevity
return Ok();
}
A simple example of a unit test for the above method could look something like this...
[TestMethod]
public void Register_ReturnErrorsWithBadRequest_IfValidationFails() {
//Arrange
PostUserRegistration model = new PostUserRegistration {
Name = "Wai Yan Hein",
Email = "waiyanhein#gmail.com",
Password = ""
};
var accRepoMock = new Mock<IAccountRepo>();
var controller = new AccountsController(accRepoMock.Object);
controller.ModelState.AddModelError("", "Faking some model error");
//Act
var response = controller.Register(model) as InvalidModelStateResult; //<-- Note the cast here
//Assert
Assert.IsNotNull(response);
}
If the injected dependency is not going to be referenced/invoked in the method under test you could also forego the mock and inject null. That however is dependent on code not provided in the original question.
I'm trying to learn about Unit Testing with the new VS2013 Default MVC w/ Authentication Project. One of the first things I want to test is registering a user. (I know I probably don't need to unit test this since it's already MS tested code but I want to use this to understand the basics). I've also heard that the new Membership code is more 'testable' so I don't need to create my own membership interfaces, etc...
I'm using NSubstitute as a faking framework.
Looking at the Account Controller -> Register() async method
namespace WebApplication1.Controllers
{
[Authorize]
public class AccountController : Controller
{
public AccountController()
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
{
}
public AccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
public UserManager<ApplicationUser> UserManager { get; private set; }
...
//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser() { UserName = model.UserName };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "Home");
}
else
{
AddErrors(result);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
If I wanted to write a simple test (ex. Register_RegisterValidUser), how would I do this? I know I need to substitute for the UserManager somehow but this did not work for me:
var substitute = Substitute.For<UserManager<ApplicationUser>>();
I also understand that I need to bypass the async Task<> functions using Task.FromResult but I'm not sure how to return a valid objects from the CreateAsync() and the SigninAsync() methods.
Can somebody help with some sample test code? Many thanks!
To mock the user manager with NSubstitute you have to use this:
var userStore = Substitute.For<IUserStore<ApplicationUser>>();
var userManager = Substitute.For<UserManager<ApplicationUser>>(userStore);
Now you can fake the methods result too. For example:
userManager.FindByNameAsync(Arg.Any<string>()).Returns(Task.FromResult(new ApplicationUser()));
Hope this help you.
Test Guidance
You can Unit Test couple of behaviours, but I will just show you the direction for a single Unit test that just verify whether receive the correct RedirectToAction value. For example,
return RedirectToAction("Index", "Home");
Improving the Testability
In your question you mentioned
I've also heard that the new Membership code is more 'testable' so I
don't need to create my own membership interfaces, etc..
While this is true, I would make a small adjustment so we can make your implementation bit more testable. This way your Unit Test can purely concentrate on the specific behaviour your going test. In other words we can make you SUT (System Under Test) more testable.
await SignInAsync(user, isPersistent: false);
I believe SignInAsync is a private method. There should be some behavior in this method you can probably extract out to a seperate implementation which you can inject in to the SUT. We can call this ISignInManager
public interface ISignInManager {
Task SignInAsync(ApplicationUser user, bool isPersistent);
}
The benefit of this is that now you can inject the behaiovr of an ISignInManager to perform the SignIn tasks and your SUT become more testable. You should see that there will be less mocking/stubbing in your Unit test and make your test easier to write and understand.
Unit Test
You can take the advantage of new async/await usage of the MSTest method. This simplifies complicated and unreliable tests which we used to write.
A Unit Test that verify the correct redirect route controller/action methods, can be written as below.
[TestMethod]
public async Task Register_RegisterValidUser_EnsureRedirectToIndexActionHomeController()
{
// Arrange
var userManagerStub = Substitute.For<IUserManager<ApplicationUser>>();
var tcs = new TaskCompletionSource<IdentityResult>();
tcs.SetResult(new IdentityResult(true));
userManagerStub.CreateAsync(Arg.Any<ApplicationUser>(), Arg.Any<string>()).Returns(tcs.Task);
var signInManagerStub = Substitute.For<ISignInManager>>();
signInManagerStub.Setup(s => s.SignInAsync(It.IsAny<ApplicationUser>(), It.IsAny<bool>())).Returns(Task.FromResult(true));
var sut = new AccountController(userManagerStub) { SignInManager = signInManagerStub.Object };
// Act
var result = await sut.Register(new RegisterViewModel() { Password = "fakePw" }) as RedirectToRouteResult;
// Assert
Assert.AreEqual<string>("Index", result.RouteValues["action"].ToString());
Assert.AreEqual<string>("Home", result.RouteValues["controller"].ToString());
}
The above uses NSubstitute as the isolation framework, but if anyone interested in the Moq version, please see below.
[TestMethod]
public async Task Register_RegisterValidUser_EnsureRedirectToIndexHome()
{
// Arrange
var userManagerStub = new Mock<IUserManager<ApplicationUser>>();
var tcs = new TaskCompletionSource<IdentityResult>();
tcs.SetResult(new IdentityResult(true));
userManagerStub.Setup(s => s.CreateAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>())).Returns(tcs.Task);
var signInManagerStub = new Mock<ISignInManager>();
signInManagerStub.Setup(s => s.SignInAsync(It.IsAny<ApplicationUser>(), It.IsAny<bool>())).Returns(Task.FromResult(true));
var sut = new AccountController(userManagerStub.Object) {SignInManager = signInManagerStub.Object};
// Act
var result = await sut.Register(new RegisterViewModel() { Password = "fakePw" }) as RedirectToRouteResult;
// Assert
Assert.AreEqual<string>("Index", result.RouteValues["action"].ToString());
Assert.AreEqual<string>("Home", result.RouteValues["controller"].ToString());
}
All,
I'm developing and unit testing an interactive voice application using ASP.NET MVC 3 whose controllers return Views containing VoiceXML. I'd like to create unit tests that capture the actual VoiceXML output so I can schema-validate it.
My reading and testing have taken me to Scott H's FakeHttpContext that uses Moq, as well as several responses here. Everything compiles correctly, and I'm trying to do something like the following:
[TestMethod]
public void WelcomeTest1()
{
EmergencyController controller = new EmergencyController();
controller.ControllerContext = new ControllerContext(MvcMockHelpers.FakeHttpContext("~/Emergency/Welcome"), new RouteData(), controller);
ViewResult result = (controller.Welcome()) as ViewResult;
.
.
Assert.IsTrue(controller.ControllerContext.HttpContext.Response.OutputStream.Length > 0);
// assert schema validation on the output here
}
However, stepping through this, I can see that the Welcome view being called, but I'm looking for something in the Response.Output and not finding anything. The mock is set up as follows, in hope that setting CallBase to true would actually write something out. I found some code that I added to the FakeHttpContext constructor that supposedly invokes a StringWriter, but to no avail:
public static HttpContextBase FakeHttpContext()
{
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>() { CallBase = true };
var response = new Mock<HttpResponseBase>();
var session = new Mock<HttpSessionStateBase>();
var server = new Mock<HttpServerUtilityBase>();
context.Setup(ctx => ctx.Request).Returns(request.Object);
context.Setup(ctx => ctx.Response).Returns(response.Object);
context.Setup(ctx => ctx.Session).Returns(session.Object);
context.Setup(ctx => ctx.Server).Returns(server.Object);
response.Setup(r => r.OutputStream).Returns(new MemoryStream());
response.Setup(r => r.Headers).Returns(new NameValueCollection());
var writer = new StringWriter();
var wr = new SimpleWorkerRequest("", "", "", "", writer);
HttpContext.Current = new HttpContext(wr);
return context.Object;
}
I'm sure I'm missing something obvious, but I'm stumped right now.
Thanks
Jim Stanley
Blackboard Connect
The result doesn't get populated in the ViewResult. In other words, the view isn't rendered by you calling return View() in your controller, rather mvc takes the viewresult and renders it at a later time in the request-sycle. What you need to do is to create a render-function for ViewResults, like this one:
using System;
using System.IO;
using System.Web.Mvc;
namespace CoPrice.Helpers
{
public static class ViewRendrer
{
public static string ToHtml(this ViewResult result, Controller controller)
{
controller.ViewData.Model = result.Model;
try
{
using (StringWriter sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, result.ViewName);
ViewContext context = new ViewContext(controller.ControllerContext, viewResult.View, result.ViewData, result.TempData, sw);
viewResult.View.Render(context, sw);
return sw.GetStringBuilder().ToString();
}
}
catch (Exception e)
{
return e.ToString();
}
}
}
}
Then you can do result.ToHtml(controller) to get the actual data (this works for RazorViews only I think, though I'm not sure, that's what I've used it for at least).
If you look at the example at this link:
http://www.atlanticbt.com/blog/asp-net-mvc-using-ajax-json-and-partialviews/
How would one write a unit test for the JsonAdd method? I have a similar situation in my own code, but the RenderPartialViewToString errors when calling:
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView
I've tried different ways of trying to stub that call to no avail. Any help appreciated. Thanks.
I had a lot of trouble to make unit test working with RenderPartialViewToString.
I succeeded by doing 2 things.
I had to mock the view engine and the controller context.
Here the code :
public ViewEngineResult SetupViewContent(string viewName, string viewHtmlContent)
{
var mockedViewEngine = new Mock<IViewEngine>();
var resultView = new Mock<IView>();
resultView.Setup(x => x.Render(It.IsAny<ViewContext>(), It.IsAny<TextWriter>()))
.Callback<ViewContext, TextWriter>((v, t) =>
{
t.Write(viewHtmlContent);
});
var viewEngineResult = new ViewEngineResult(resultView.Object, mockedViewEngine.Object);
mockedViewEngine.Setup(x => x.FindPartialView(It.IsAny<ControllerContext>(), viewName, It.IsAny<bool>()))
.Returns<ControllerContext, string, bool>((controller, view, useCache) =>
{
return viewEngineResult;
});
mockedViewEngine.Setup(x => x.FindView(It.IsAny<ControllerContext>(), viewName, It.IsAny<string>(), It.IsAny<bool>()))
.Returns<ControllerContext, string, string, bool>((controller, view, masterName, useCache) =>
{
return viewEngineResult;
});
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(mockedViewEngine.Object);
return viewEngineResult;
}
public void SetContext(ref PointCollecteLivraisonController controller)
{
SetupViewContent("MyViewName", "TheViewContent");
var httpContextBase = new Mock<HttpContextBase>();
var httpRequestBase = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var session = new Mock<HttpSessionStateBase>();
var routes = new RouteCollection();
RouteConfigurator.RegisterRoutes(routes);
var routeData = new RouteData();
routeData.Values.Add("controller", "PointCollecteLivraison");
routeData.Values.Add("action", "RechercheJson");
httpContextBase.Setup(x => x.Response).Returns(response.Object);
httpContextBase.Setup(x => x.Request).Returns(httpRequestBase.Object);
httpContextBase.Setup(x => x.Session).Returns(session.Object);
session.Setup(x => x["somesessionkey"]).Returns("value");
httpRequestBase.Setup(x => x.Form).Returns(new NameValueCollection());
controller.ControllerContext = new ControllerContext(httpContextBase.Object, routeData, controller);
controller.Url = new UrlHelper(new RequestContext(controller.HttpContext, routeData), routes);
}
And that is the way i use it all :
PointCollecteLivraisonController controller = new PointCollecteLivraisonController();
SetContext(ref controller);
Here are my sources :
View engine mocking : http://thoai-nguyen.blogspot.fr/2011/04/test-mock-mvc-view-engine.html
Controller context mocking : ASP.NET MVC - Unit testing RenderPartialViewToString() with Moq framework?
Hope this help.
Since ViewEninges is a static class, you can't mock it with RhinoMocks. I think your best bet is to create a "partial view renderer" interface. An interface is mockable so you'll be able to stub out the complexity of rendering the view. Here's some quick pseudo-code thrown together.
First, define the partial view renderer interface:
public interface IRenderPartialView
{
string Render(string viewName, object model);
}
Then, change your base class' RenderPartialViewToString to be the implementation of IRenderPartialView.Render:
public abstract class BaseController : Controller, IRenderPartialView
{
...
public string Render(string viewName, object model)
{
// same code as RenderPartialViewToString
}
}
Now we need to change your controller constructors so we can inject an IRenderPartialView during testing -- but use the base class one during production. We can accomplish this by using a pair of constructors:
public class YourController : BaseController
{
private IRenderPartialView partialRenderer;
public YourController()
{
SetRenderer(this);
}
public YourController(IRenderPartialView partialRenderer)
{
SetRenderer(partialRenderer);
}
private void SetRenderer(IRenderPartialView partialRenderer)
{
this.partialRenderer = this;
}
}
Now, JsonAdd can call the partial view renderer:
public JsonResult JsonAdd(AddPersonViewModel AddPersonModel)
{
...
return Json(new
{
Success = true,
Message = "The person has been added!",
PartialViewHtml = partialRenderer.Render("PersonList", new PersonListViewModel {PersonList = _personList})
});
}
So, during testing, you'll mock out an IRenderPartialView and send that to the constructor that accepts an IRenderPartialView. During production, when ASP.NET MVC calls your default constructor, it will use the controller as the renderer (which has the implementation of IRenderPartialView.Render inside the base class).