Mvc.net Unit test with a nullable parameter - asp.net-mvc

I am new for unit test with Moq and Nunit. I have a simple unit test for getting a product list. But the test result didn't turn out as expected.
ProductManagementController action is:
public ViewResult Index(int? id)
{
return View(_ProductRepo.GetProductList(id));
}
ProductRepository is:
public IList<Product> GetProductList(int? id)
{
if (id == null)
{
return (db.Products).ToList();
}
else
{
return db.Products.Where(i => i.CategoryId == id).ToList();
}
}
I have two tests setup, but only the first test(get all products list) is fine.
[TestFixture]
public class Test_ProductManagement
{
private List<Product> products;
private List<Category> categories;
private Mock<IProductRepository> mockProducts;
private ProductManagementController target;
[TestFixtureSetUp]
public void Initialize()
{
images = new List<Product> {
new Product{Id = 1, Name = "Boat", CategoryId = 1 },
new Product{Id = 2, Name = "Picture Frame",CategoryId = 2 }
};
categories = new List<Category> {
new Category { Id = 1, Name = "Outdoors" },
new Category { Id = 2, Name = "Housewares" }
};
mockProducts = new Mock<IProductRepository>();
mockProducts.Setup(m => m.GetProductList(It.IsAny<int>())).Returns(products);
target = new ProductManagementController(mockProducts.Object);
}
[Test]
public void Index_Contains_All_Products()
{
//Action
List<Product> result = ((IEnumerable<Product>)target.Index(It.IsAny<int>()).ViewData.Model).ToList();
//Assert
Assert.AreEqual(2, result.Length);
Assert.AreEqual("Boat", result[0].Name);
Assert.AreEqual("Picture Frame", result[1].Name);
}
[Test]
public void Index_Get_ImageList_By_CategoryId()
{ //Arrange
int id = 2;
//Action
List<Product> result = ((IEnumerable<Product>)target.Index(id).ViewData.Model).ToList();
//Assert
Assert.AreEqual(1, result.Count());
Assert.AreEqual("Picture Frame", result[0].Name);
}
The 2nd test always return a full product list which include 2 products while I only expect 1 returned from Assert.AreEqual(1,result.Count());
I can't figure out why test code always take the id as a null parameter in the above index call: target.Index(id) . However all my project codes run correctly in the browsers.
Does anyone has a clue? Thanks.

I can't figure out why test code always take the id as a null parameter in the above index call: target.Index(id)
It doesn't. You don't show all code (specifically how your controller handles the repository injection) and you seem to have renamed at least the products / images field, but the code works just fine.
You call target.Index(id), which in turn calls _ProductRepo.GetProductList(id). I assume this is your mock being called, which is Setup() by you to always return the entire product list.
The mock does exactly what you ask it to, no ProductRepository is used in this code, so your if (id == null) is never executed.
In order to fix this, you must Setup() your mock differently in each test method, or setup both cases in advance:
mockProducts.Setup(m => m.GetProductList(null)).Returns(products);
mockProducts.Setup(m => m.GetProductList(2)).Returns(new List<Product>{products[1]});
Of course you want to setup the latter call somewhat less specific, but I hope you see where you can fix this.

Related

Testing a method in MVC which makes calls to Repositories

I have a MVC method like so:
public ActionResult ChangeStatus(string productId, string statusToChange)
{
var productToChangeStatus = _updateProductRepository.GetUpdateProduct(productId);
if (statusToChange.ToLower() == ChangeStatusTo.Disable)
{
productToChangeStatus.Active = "false";
}
else
{
productToChangeStatus.Active = "true";
}
_updateProductsManager.UpsertProduct(productToChangeStatus);
return Json(new { success = true });
}
This method gets an existing product based on the 'productId', changes the 'Active' property on it based on the 'statusToChange' value, saves it back and returns a Json with success.
The test setup is like so:
private ProductController _controller;
private Mock<IUpdateProductRepository> _iProductRepository;
[TestInitialize]
public void TestSetup()
{
_iProductRepository = new Mock<IUpdateProductRepository>();
_controller = new ProductController(_iProductRepository.Object);
}
Wrote a test method like so:
[TestMethod]
public void Disable_A_Product_Which_Is_Currently_Enabled()
{
const string productId = "123";
var productBeforeStatusChange = new Product()
{
Active = "true",
Id = new Guid().ToString(),
Name = "TestProduct",
ProductId = "123"
};
var productAfterStatusChange = new Product()
{
Active = "false",
Id = new Guid().ToString(),
Name = "TestProduct",
ProductId = "123"
};
_iProductRepository.Setup(r => r.GetUpdateProduct(productId)).Returns(productBeforeStatusChange);
_iProductRepository.Setup(r => r.UpsertProduct(productBeforeStatusChange)).Returns(productAfterStatusChange);
var res = _controller.ChangeStatus("123", "disable") as JsonResult;
Assert.AreEqual("{ success = true }", res.Data.ToString());
}
The test fails with this error:
Object reference not set to an instant of the object.
On debugging I found that it fails inside the
if(...)
condition where the actual setting of the Active property is happening.
Since the productId that's being passed is not real a product object can't be retrieved for the code to work on.
I tried to use Mock but I think my usage is not correct.
So what I want to know is, how to test a method like this where a method that returns an ActionResult is in turn calling the repository to work with object(s).
Thanks in advance.
You seems to be missing setup for
_updateProductsManager.UpsertProduct()
The way you setup GetUpdateProduct() method you ought to setup UpsertProduct() on the mock instance.

Why does one Web API method work, whereas the other does not?

One of my Web API methods works perfectly, and the other not at all.
By works perfectly, I mean this:
The other one, though, doesn't seem to even know about itself. It answers the browser request with:
The code seems to be set up the same for both of them, so I don't know why one works like a charm and the other fails so thuddily.
The pertinent code is:
CONTROLLER
public class DepartmentsController : ApiController
{
private readonly IDepartmentRepository _deptsRepository;
public DepartmentsController(IDepartmentRepository deptsRepository)
{
if (deptsRepository == null)
{
throw new ArgumentNullException("deptsRepository is null");
}
_deptsRepository = deptsRepository;
}
[Route("api/Departments/Count")]
public int GetCountOfDepartmentRecords()
{
return _deptsRepository.Get();
}
[Route("api/Departments")]
public IEnumerable<Department> GetBatchOfDepartmentsByStartingID(int ID, int CountToFetch)
{
return _deptsRepository.Get(ID, CountToFetch);
}
REPOSITORY
public class DepartmentRepository : IDepartmentRepository
{
private readonly List<Department> departments = new List<Department>();
public DepartmentRepository()
{
using (var conn = new OleDbConnection(
#"Provider=Microsoft.ACE.OLEDB.12.0;User ID=Freebo;Password=RunningOnEmpty;Data Source=C:\CDBWin\DATA\CCRDAT42.MDB;Jet OLEDB:System database=C:\CDBWin\Data\nrbq.mdw"))
{
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "SELECT td_department_accounts.dept_no, IIF(ISNULL(t_accounts.name),'No Name provided',t_accounts.name) AS name FROM t_accounts INNER JOIN td_department_accounts ON t_accounts.account_no = td_department_accounts.account_no ORDER BY td_department_accounts.dept_no";
cmd.CommandType = CommandType.Text;
conn.Open();
int i = 1;
using (OleDbDataReader oleDbD8aReader = cmd.ExecuteReader())
{
while (oleDbD8aReader != null && oleDbD8aReader.Read())
{
int deptNum = oleDbD8aReader.GetInt16(0);
string deptName = oleDbD8aReader.GetString(1);
Add(new Department { Id = i, AccountId = deptNum, Name = deptName });
i++;
}
}
}
}
}
public int Get()
{
return departments.Count;
}
private Department Get(int ID) // called by Delete()
{
return departments.First(d => d.Id == ID);
}
If entering:
http://shannon2:28642/api/Departments/Count
in the browser works to execute the Controller's GetCountOfDepartmentRecords() method, why does entering:
http://localhost:28642/api/Departments/5/6
(or:
http://localhost:28642/api/Departments/1/5
etc) not work to execute the Controller's GetBatchOfDepartmentsByStartingID() method?
Your route is missing its parameters.
[Route("api/Departments/{ID:int}/{CountToFetch:int}")]
This question looks similar to your other question below:
Why is my Web API call returning "No action was found on the controller 'DPlatypus' that matches the request"?
If you are expecting the values to come from a non-query string part of a url, you need to define them in the route template. So, it should be
[Route("api/Departments/{id}/{countToFetch}")]
Following is a good article to read about routing and action selection in Web API:
http://www.asp.net/web-api/overview/web-api-routing-and-actions

Unit Testing a RedirectToAction with parameter

I have an MVC Controller Class that I am trying to Unit Test.
The particular ActionResult is like this
public ActionResult Create(Shipment newShipment)
{
do some stuff to create a shipmentID
...
return RedirectToAction("AddUnit",newShipment.ShipmentID);
}
I have mocked up the controller context etc and now I want to test that the newShipment.ShipmentID passed to the RedirectToAction call is what I expect.
I have a test (with lots of mocking of things in the setup phase)
[Test]
public void CreateSuccess()
{
//Arrange
var shipment = new Shipment();
shipment.Widgets = 2; //Make sure it a valid shipment otherwise
//Act
var result = controller.Create(shipment) as RedirectToRouteResult;
//Assert
Assert.IsNotNull(result);
Assert.AreEqual("AddUnits", result.RouteValues["action"]);
Assert.IsNull(result.RouteValues["controller"]);
...
And now I want to find an Assert to check that the shipmentID I pass to RedirectToAction is the right one. How do I retrieve its value?
(I believe this code works for real (ie the actual view gets the correct shipmentID) but I want to write a unit test ).
Actually, RedirectToActions can take parameters; below is a simplified example of how I tested for correct parameters in one. I'm using NUnit & FluentAssertions here.
[HttpPost]
public ActionResult RedirectMethod()
{
return RedirectToAction("Index", "Home", new { parameter = "Value" });
}
and then the test:
[Test]
public void RedirectSetsExpectedParameters()
{
var result = controller.RedirectMethod();
var redirectResult = result.As<RedirectToRouteResult>();
var expectedRedirectValues = new RouteValueDictionary
{
{ "parameter", "Value" },
{ "action", "Index" },
{ "controller", "Home" }
};
redirectResult
.RouteValues
.ShouldBeEquivalentTo(expectedRedirectValues,
"The redirect should look as I expect, including the parameters");
}
Here i given one sample for Redirect to action
public ActionResult Signupsuccess(string account_code, string plan)
{
..........
do some stuff
return RedirectToAction("SubscriptionPlan", "Settings");
}
I have mocked up controllercontext and passed some parameter to RedirectToAction call from controller to test method.Finally it tested both the expected and actual
[TestMethod()]
public void SignupsuccessTest()
{
HomeController target = new HomeController(); // TODO: Initialize to an appropriate value
string account_code = "B898YB7"; // TODO: Initialize to an appropriate value
string plan = "Application-BASIC"; // TODO: Initialize to an appropriate value
var ControllerContext = new Mock<ControllerContext>();
var context = target.HttpContext;
ControllerContext.SetupGet(p => p.HttpContext.Session["MerchantID"]).Returns("15");
ControllerContext.SetupGet(p => p.HttpContext.Session["FriendlyIdentifier"]).Returns("3d649876-19f5-48d2-af03-ca89083ae712");
target.ControllerContext = controllerContext.Object;
var action = (RedirectToRouteResult)target.Signupsuccess(account_code, plan);
action.RouteValues["action"].Equals("SubscriptionPlan");
action.RouteValues["controller"].Equals("Settings");
Assert.AreEqual("SubscriptionPlan", action.RouteValues["action"]);
Assert.AreEqual("Settings", action.RouteValues["controller"]);
}
I Hope really it will helpful for you.Thank You

unit testing of very small asp.net mvc actions returning json

The first line of my action is tested with an extra integration test.
The second line is tested with an extra unit test for automapper mapping stuff
The third line is untested then.
The below unit test does it test the third line? because it just tests the return type.
This seems stupid or too trivial too me. What else should the method return????
There is no if/else logic inside this action. Therefore just testing for type == JsonNetResult seems superfluid for me. I would not even realize in my unit test if someone removes the success = true anonymous type.
Should I rather test the data of the JsonNetResult with QUnit?
I would be glad about some guidance and tips because the actions returning Json data drive me crazy... Its just fetch data from db and put it inside the JsonNetResult object.
Action
[HttpGet]
public ActionResult GetTemplateRootUnits(int templateId)
{
IEnumerable<Unit> units = _dataProvider.GetTemplateRootUnits(templateId);
IEnumerable<UnitTreeViewModel> unitTreeViewModels = Mapper.Map<IEnumerable<Unit>, IEnumerable<UnitTreeViewModel>>(units);
return new JsonNetResult(new { data = unitTreeViewModels, success = true });
}
Unit test
[Test]
public void GetTemplateRootUnits_TemplateExists_ReturnsJsonNetResult()
{
// ARRANGE
Mock<IUnitDataProvider> mock1 = new Mock<IUnitDataProvider>();
Mock<IMappingEngine> mock2 = new Mock<IMappingEngine>();
Mock<ControllerContext> mock3 = new Mock<ControllerContext>();
UnitController controller = new UnitController(mock1.Object, mock2.Object);
mock1.Setup(m => m.GetTemplateRootUnits(1)).Returns(new List<Unit>
{
new Unit{ UnitId = 1, Name = "Name1", HasChildren = false},
new Unit{ UnitId = 2, Name = "Name2", HasChildren = false},
new Unit{ UnitId = 3, Name = "Name3", HasChildren = false},
});
var unitTreeViewModels = new List<UnitTreeViewModel>
{
new UnitTreeViewModel { Id = 1, Name = "Name1", HasChildren = false},
new UnitTreeViewModel { Id = 2, Name = "Name2", HasChildren = false},
new UnitTreeViewModel { Id = 3, Name = "Name3", HasChildren = false},
};
// Thats the way AutoMapper is mocked
mock2.Setup(m => m.Map<IEnumerable<Unit>, IEnumerable<UnitTreeViewModel>>(It.IsAny<IEnumerable<Unit>>())).Returns(unitTreeViewModels);
// ACT
ActionResult result = controller.GetTemplateRootUnits(1);
// ASSERT - check that the dataProvider.GetTestplanRootUnits() was called
mock1.Verify(m => m.GetTemplateRootUnits(1));
// ASSERT
Assert.IsInstanceOfType(typeof(JsonNetResult), result);
}
JsonNetResult.cs
public class JsonNetResult : ContentResult
{
private readonly object _data;
public JsonNetResult(object data)
{
_data = data;
}
public override void ExecuteResult(ControllerContext context)
{
Content = JsonConvert.SerializeObject(_data);
ContentType = "application/json";
base.ExecuteResult(context);
}
public object Data { get { return _data; } }
}
You haven't shown what the JsonNetResult class is, but I will assume that it is some custom action result using JSON.NET as serializer instead of the default JavaScriptSerializer. I will also assume that this class exposes a public property of type object called Data holding the model that is to be serialized:
public class JsonNetResult: ActionResult
{
public JsonNetResult(object data)
{
Data = data;
}
public object Data { get; private set; }
...
}
So you could test the data inside the result:
// ASSERT
Assert.IsInstanceOfType(typeof(JsonNetResult), result);
var jsonResult = result as JsonNetResult;
var data = new RouteValueDictionary(jsonResult.Data);
Assert.IsTrue((bool)data["success"]);
Assert.IsInstanceOfType(data["data"], typeof(IEnumerable<UnitTreeViewModel>));
Assert.AreEqual(unitTreeViewModels, data["data"]);
You don't need to test type of return value. You need to set type of return value in signature of method.
public JsonNetResult GetTemplateRootUnits(int templateId);

Expression Equality or Equivalence from Multiple Projects

It is understood that:
Expression<Func<string, bool>> first = x => x.Length == 4;
Expression<Func<string, bool>> second = x => x.Length == 4;
Console.WriteLine(first.Equals(second)); // Output is "False"
However, examining the strings of each expression does show equality:
Expression<Func<string, bool>> first = x => x.Length == 4;
Expression<Func<string, bool>> second = x => x.Length == 4;
Console.WriteLine(first.ToString().Equals(second.ToString())); // Output is "True"
This idea was a culmination of different posts...
http://www.codethinked.com/Comparing-Simple-Lambda-Expressions-With-Moq
Moq'ing methods where Expression<Func<T, bool>> are passed in as parameters
Verify method was called with certain linq expression (moq)
The intent:
I am writing an MVC application using the repository pattern such that
public class MyController : Controller
{
public Repository.IRepository Repository { get; set; }
public MyController()
{
this.Repository = new Repository.CommonRepository();
}
public MyController(Repository.IRepository repository)
{
this.Repository = repository;
}
[HttpPost]
public ActionResult Create(Domain.Common.Object1 o1)
{
if (ModelState.IsValid)
{
// Additional validation
o1.Name = o1.Name.Trim();
if (this.Repository.Any<Domain.Common.Object1>(a => a.Name.ToLower() == plant.Name.ToLower()))
this.ModelState.AddModelError("Name", "Duplicate found.");
}
if (ModelState.IsValid)
{
var entity = this.Repository.Add(o1);
if (Request.IsAjaxRequest())
return this.Json(new { Completed = true, Id = entity.Id });
return RedirectToAction("Details", new { id = entity.Id });
}
if (Request.IsAjaxRequest())
return PartialView("_Create", o1);
return View("Create", o1);
}
}
Repository is a completely separate project as is the domain. My repository code is setup so that I can use the one repository to query any object based upon the generic:
public IQueryable<T> GetAll<T>() where T : AbstractEntity
{
return this.DbContext.Set<T>();
}
Note: AbstractEntity is a domain abstract class all of my POCO objects inherit from.
Everything is fine when using Moq to unit test the controller :
[TestMethod]
public void Create_Post_DuplicateNameAddsError()
{
// Arrange
var repository = new Mock<Repository.IRepository>();
repository.Setup(a => a.Any<Domain.Common.Object1>(It.IsAny<System.Linq.Expressions.Expression<Func<Domain.Common.Object1, bool>>>()))
.Returns(true);
var controller = ControllerFactory<MyController>.GetController();
controller.Repository = repository.Object;
var model = new Domain.Common.Object1()
{
Id = Guid.NewGuid()
,
Name = "Name"
};
// Act
var result = controller.Create(model) as ViewResult;
// Assert
Assert.IsFalse(controller.ModelState.IsValid);
Assert.IsNotNull(result);
Assert.AreEqual("Create", result.ViewName, false);
Assert.AreEqual(model, result.Model);
}
Note: ControllerFactory is a way to generate a controller with certain properties filled, such as Request, Response, User, Request.Headers ect...
Where this fails is if I have to use IRepository.Any(predicate) more than once, or any method that uses expressions that is called more than once. I need it to say true for one and false for another. If the expression strings were a match, this would be a non-issue, but as everything is in different projects the expression strings come out as:
a => (a.Name.ToLower() == value(foo.Web.Tests.Controllers.Object1ControllerTests+<>c__DisplayClass3).ob1.Name.ToLower())
a => (a.Name.ToLower() == value(foo.Controllers.MyController+<>c__DisplayClass1).ob1.Name.ToLower())
The difference lies in the value function. I have tried matching from Regular Expressions, which works, but is ugly as you have to escape every .<>(), which in turn makes it very difficult to maintain.
I tried using Matt Meber's Expression Equality Comparer, but they are not equal due to that value function (my belief).
Suggestions?

Resources