Unit Testing MVC Authentication VS 2013 - unit-testing

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());
}

Related

Testing Using NUnit and Moq: use case

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.

Unable to mock Configuration.Formatters using Moq

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.

Unit testing when Database is involved

I'm quite new to unit testing and I need an hand to understand if I'm doing things in the correct way. My major problem is regarding the DB testing... Here's my code then I'll expose my perplexities
Consider this class that's an item of a pipeline I've to perform
public class RetrieveApplicationUsernamePipelineStep : IPipelineStep
{
public const string RetrieveApplicationUsernameKey = "RetrieveApplicationUsername";
private readonly IRetrieveApplicationUserRepository repository;
public int Order => 3;
public string Name => RetrieveApplicationUsernameKey;
public RetrieveApplicationUsernamePipelineStep(IRetrieveApplicationUserRepository repository)
{
this.repository = repository;
}
public async Task<IDictionary<string, object>> Action(IDictionary<string, object> context)
{
string res = await repository.GetApplicationUser(context);
context[Resources.ApplicationUser] = res;
return context;
}
}
I wrote the following tests
[TestFixture]
public class RetrieveApplicationUsernamePipelineStepTests
{
private IRetrieveApplicationUserRepository retrieveApplicationUserRepository;
[OneTimeSetUp]
public void Start()
{
var configuration = new ConfigurationFromConfigFile();
retrieveApplicationUserRepository = new RetrieveApplicationUserRepository(configuration);
}
[Test]
public async Task ActionSuccessfullyCompleted()
{
var context = new Dictionary<string, object>();
var repository = Substitute.For<IRetrieveApplicationUserRepository>();
repository.GetApplicationUser(context).Returns("user1");
var pipeline = new RetrieveApplicationUsernamePipelineStep(repository);
var res = await pipeline.Action(context);
Assert.IsNotNull(res[Resources.ApplicationUser]);
Assert.IsNotEmpty((string)res[Resources.ApplicationUser]);
}
[Test]
public void ActionFailingCompleted()
{
var context = new Dictionary<string, object>();
var repository = Substitute.For<IRetrieveApplicationUserRepository>();
repository.GetApplicationUser(context).Throws(new UserMappingNotFoundException());
var pipeline = new RetrieveApplicationUsernamePipelineStep(repository);
Assert.ThrowsAsync<UserMappingNotFoundException>(async () => await pipeline.Action(context));
}
[Test]
public void NameTest()
{
var pipeline = new RetrieveApplicationUsernamePipelineStep(retrieveApplicationUserRepository);
Assert.IsTrue(pipeline.Name == RetrieveApplicationUsernamePipelineStep.RetrieveApplicationUsernameKey);
}
[Test]
public void OrderTest()
{
var pipeline = new RetrieveApplicationUsernamePipelineStep(retrieveApplicationUserRepository);
Assert.IsTrue(pipeline.Order == 3);
}
}
And those test works fine since for ActionSuccessfullyCompleted and ActionFailingCompleted I substitute the IRetrieveApplicationUserRepository's result with my expected one.
The real implementation of ther repository is
public class RetrieveApplicationUserRepository : IRetrieveApplicationUserRepository
{
#region Variables
private readonly IConfiguration configuration;
#endregion
#region Ctor
public RetrieveApplicationUserRepository(IConfiguration configuration)
{
this.configuration = configuration;
}
#endregion
#region IRetrieveApplicationUserRepository
public async Task<string> GetApplicationUser(IDictionary<string, object> context)
{
if (configuration.AppSettings[Resources.ApplicationUserFromDomainUserKey] == null)
throw new KeyNotFoundException(Resources.ApplicationUserFromDomainUserKey);
if (string.IsNullOrEmpty(configuration.ConnectionString))
throw new NullReferenceException();
string storedProcedure = configuration.AppSettings.Get(Resources.ApplicationUserFromDomainUserKey);
string result;
using (var sqlConnection = new SqlConnection(configuration.ConnectionString))
{
using (var sqlCommand = new SqlCommand(storedProcedure, sqlConnection))
{
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.Parameters.AddWithValue("#DOMAINUSER", context[Resources.DomainUser]);
sqlCommand.Parameters.AddWithValue("#DOMAIN", context[Resources.DomainName]);
sqlCommand.Parameters.AddWithValue("#APPID", context[Resources.ApplicationId]);
sqlConnection.Open();
result = (string)await sqlCommand.ExecuteScalarAsync();
}
}
if (result == null)
throw new UserMappingNotFoundException();
return result;
}
#endregion
}
Here're the questions :
Are the test I wrote correct?
I've seen using Resharper's Code Coverage that it wants me to test-cover the properties...is there a way I can avoid this? is this test meaningful?
What's your approach when you've to unit test component that're related to DB? Have you got a real-db that's used for test? Consider that the real DB is about 10Gb so I don't want to have a copy as mdf (condider I can have this) just to test a small portion of the DB
Talking with my colleagues they told me to use test just for TDD while I wish to use them to avoid regressions
Going back to the DB question, I don't want to have a test where I write if username is "John" and maybe tomorrow John user won't be present in the DB anymore,so that the test I expect to pass wont' pass anoymore
The usual approach is to isolate the database side with an abstraction, so you can provide a test dummy (mock, fake, etc) of that abstraction. Only test an actual database when you do the integration testing.
For the tests of database stored procedures, you may well want a different test harness, creating a new test database in memory (equivalently, in a RAM-backed filesystem). You only need to populate enough data for the individual test (we're doing functional testing here, not performance testing), and you may be able to retain table structure across tests with judicious use of rollback.
I have done this, but it's some time ago, so I'll refrain from giving examples that may be no longer state-of-the-art (even if the code does still exist, and if I could find it).

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.

Using Moq to mock a repository that returns IQueryable<MyObject>

How to I setup my Moq to return some values and having the tested service select the right one?
IRepository:
public interface IGeographicRepository
{
IQueryable<Country> GetCountries();
}
Service:
public Country GetCountry(int countryId)
{
return geographicsRepository.GetCountries()
.Where(c => c.CountryId == countryId).SingleOrDefault();
}
Test:
[Test]
public void Can_Get_Correct_Country()
{
//Setup
geographicsRepository.Setup(x => x.GetCountries()).Returns()
//No idea what to do here.
//Call
var country = geoService.GetCountry(1);
//Should return object Country with property CountryName="Jamaica"
//Assert
Assert.IsInstanceOf<Country>(country);
Assert.AreEqual("Jamaica", country.CountryName);
Assert.AreEqual(1, country.CountryId);
geographicsRepository.VerifyAll();
}
I'm basically stuck at the setup.
Couldn't you use AsQueryable()?
List<Country> countries = new List<Country>();
// Add Countries...
IQueryable<Country> queryableCountries = countries.AsQueryable();
geographicsRepository.Setup(x => x.GetCountries()).Returns(queryableCountries);
I suggest do not use AsQueryable(). it works only with some simple scenarios before you meet some specific methods on your ORM query language (Fetch, FetchMany, ThenFetchMany, Include, ToFuture and so on).
Better to use in memory database. Link below describes NHibernate Unit Testing.
We can either use a standard RDBMS or use an in memory database such as SQLite in order to get very speedy tests.
http://ayende.com/blog/3983/nhibernate-unit-testing
What you can do is write a private helper method that will generate an IQueryable of Country objects and have your mock return that.
[Test]
public void Can_Get_Correct_Country()
{
// some private method
IQueryable<Country> countries = GetCountries();
//Setup
geographicsRepository.Setup(x => x.GetCountries()).Returns(countries);
//Should return object Country with property CountryName="Jamaica"
//Call
var country = geoService.GetCountry(1);
//Assert
Assert.IsInstanceOf<Country>(country);
Assert.AreEqual("Jamaica", country.CountryName);
Assert.AreEqual(1, country.CountryId);
geographicsRepository.VerifyAll();
}