I'm trying to test a method, which relies on the value of one of the fields in my model (used as a parameter). I'm looking for help on how to mock this value, so my unit test will work.
Without setting this value, the test will follow the path to the exception.
CONTROLLER
public class StatusViewerController : Controller
{
private IERERepository _ereRepository;
//Dependency Injection
public StatusViewerController(IERERepository ereRepository)
{
_ereRepository = ereRepository;
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "RecordID,ClientNumber")] StatusViewerFormViewModel model)
{
if (ModelState.IsValid)
{
try
{
//Send to one of two functions depending on RecordID value
if (model.RecordID == null)
{
_ereRepository.StatusViewerInsert(model);
}
else
{
_ereRepository.StatusViewerUpdate(model);
}
return new HttpStatusCodeResult(HttpStatusCode.OK);
}
catch
{
throw new HttpException(500, "Internal Server Error");
}
}
else
{
throw new HttpException(400, "ModelState Invalid");
}
}
}
UNIT TEST
/// <summary>
/// Tests the Edit method for ActionResult return type
/// </summary>
[TestMethod]
public void StatusViewer_Edit_Returns_ActionResult()
{
//Arrange
var mockRepository = new Mock<IERERepository>();
StatusViewerController controller = new StatusViewerController(mockRepository.Object);
//Act
//I need to set the value of RecordID here or else this test will fail
//It will return an exception
ActionResult result = controller.Edit(It.IsAny<StatusViewerFormViewModel>());
//Assert
Assert.IsInstanceOfType(result, typeof(ActionResult));
}
Just create the model and call the method under test.
What you have not done is setup your dependency for the controller.
/// <summary>
/// Tests the Edit method for ActionResult return type
/// </summary>
[TestMethod]
public void StatusViewer_Edit_Returns_ActionResult()
{
//Arrange
var mockRepository = new Mock<IERERepository>();
mockRepository
.Setup(m => m.StatusViewerInsert(It.IsAny<StatusViewerFormViewModel>())
.Verifiable();
var controller = new StatusViewerController(mockRepository.Object);
var model = new StatusViewerFormViewModel {
RecordID = "set the value of RecordID here",
ClientNumber = "Other property value here",
//...other properties
};
//Act
ActionResult result = controller.Edit(model);
//Assert
Assert.IsInstanceOfType(result, typeof(ActionResult));
mockRepository.Verify();//verify that the repository was called.
}
Related
How to test a method which creates session inside the method. i using to do Unit test . when i call method using test case it was unable to create session inside method. can anyone please help me to create unit tests for my code below
public ActionResult InviteUser(string Id)
{
if (!string.IsNullOrEmpty(Id))
{
Session["verification_uid"] = Id;
return RedirectToAction("Login", "Account");
}
return View();
}
i have tried with following code also but it not working
[TestMethod]
public void InviteUser_ExpectRedirectActionResultReturned()
{
//Arrange
controller = new AccountController();
var mockControllerContext = new Mock<ControllerContext>();
var mockSession = new Mock<HttpSessionStateBase>();
mockSession.SetupGet(s => s["verification_uid"]).Returns("123"); //somevalue
mockControllerContext.Setup(p => p.HttpContext.Session).Returns(mockSession.Object);
controller.ControllerContext = mockControllerContext.Object;
var id = "1";
System.Web.HttpContext.Current.Session["verification_uidID"] = "12";
//Act
var result = (RedirectToRouteResult)controller.InviteUser(id);
//Assert
result.RouteValues["action"].Equals("Index");
result.RouteValues["controller"].Equals("Home");
Assert.AreEqual("Index", result.RouteValues["action"]);
Assert.AreEqual("Home", result.RouteValues["controller"]);
}
You could put the setting of the session variable into a helper class, implementing an interface that gets passed into the class which you could mock in the unit test.
public MyClass
{
private readonly ISessionHelper _helper;
public MyClass(ISessionHelper helper)
{
this._helper = helper;
}
public ActionResult InviteUser(string Id)
{
if (!string.IsNullOrEmpty(Id))
{
this._helper.SetSessionVariable("verification_uid", Id);
return RedirectToAction("Login", "Account");
}
return View();
}
}
Your helper would contain SetSessionVariable which does the setting.
Then, in your unit test, you mock ISessionHelper.
public ActionResult SomeAction(int?id)
{
MyModel model = new MyModel();
return View(model);
}
[Test]
public void Can_Open_SomeAction()
{
// controller is already set inside `SetUp` unit step.
ViewResult res = this.controller.SomeAction() as ViewResult;
var model = result.Model as MyModel;
Assert.IsNotNull(model);
}
this test passes succ. but when when change controller action to have populate combos like
public ActionResult SomeAction(int?id)
{
MyModel model = new MyModel();
this.PopulatePageCombos(id);
return View(model);
}
I'm getting error on line this.PopulatePageCombos(id);
Object reference is not set
So, how can I mock this PopulatePageCombos method in unit test?
Update:
public ActionResult SomeAction(int?id)
{
MyModel model = new MyModel();
this.PopulatePageCombos(model.Id, 100);
return View(model);
}
Update 2:
PopulatePageCombos (model, countryId, requesterId);
where model is of type MyModel, countryId is int and requesterId is int
You can create a helper class PopulatePageCombosHelper and encapsulate PopulatePageCombos method in it. So the SomeAction method would look like
public PopulatePageCombosHelper populatePageHelper;
public ActionResult SomeAction(int?id)
{
MyModel model = new MyModel();
populatePageHelper.PopulatePageCombos(id);
return View(model);
}
So then you can mock populatePageHelper
[Test]
public void Can_Open_SomeAction()
{
// controller is already set inside `SetUp` unit step.
var populatePageHelperMock = new Mock<PopulatePageCombosHelper>();
controller.populatePageHelper = populatePageHelperMock;
ViewResult res = this.controller.SomeAction() as ViewResult;
var model = result.Model as JobCreate;
//...
Assert.IsNotNull(model);
}
You can make PopulatePageCombos method virtual and override it in derived class ControllerTestable and test the ControllerTestable
public class ControllerTestable : Controller
{
public bool IsCalled = false;
public override ViewResult SomeAction()
{
IsCalled = true;
return null;
}
}
So in the test instead of creating Controller controller you can create ControllerTestable controller.
[Setup]
public void SetUp ()
{
var controller = new ControllerTestable();
//...
}
[Test]
public void Can_Open_SomeAction()
{
// controller is already set inside `SetUp` unit step.
ViewResult res = this.controller.SomeAction() as ViewResult;
var model = result.Model as JobCreate;
//...
Assert.IsTrue(controller.IsCalled);
Assert.IsNotNull(model);
}
You can partial mock the controller. Having:
public virtual void PopulatePageCombos(int? id)
{
throw new NullReferenceException();
}
public ActionResult SomeAction(int? id)
{
MyModel model = new MyModel();
this.PopulatePageCombos(id);
return View(model);
}
Then you setup the method PopulatePageCombos to do anything:
public class Default1ControllerTests
{
private Mock<Default1Controller> controllerMock;
[SetUp]
public void SetUp()
{
this.controllerMock = new Mock<Default1Controller>() { CallBase = true };
this.controllerMock.Setup(m => m.PopulatePageCombos(It.IsAny<int?>())).Callback(() => { });
}
[Test]
public void Can_Open_SomeAction()
{
// controller is already set inside `SetUp` unit step.
ViewResult res = this.controllerMock.Object.SomeAction(null) as ViewResult;
var model = res.Model as MyModel;
Assert.IsNotNull(model);
}
}
It's important to declare virtual the method to mock and specify CallBase = true on mock creation. This will call the programmed logic on methods not setup.
So, I'm starting to learn an implement UniTesting on a Web Api project I'm working on. What's happening is that when I setup a mock a call this one returns null instead of the value I'm telling to returns. I don't know why a similiar Setup works but this one just doesn't.
Here is my Test Class
namespace API.Tests.Web
{
[TestClass]
public class MaterialsControllerTest
{
private MaterialsController controller;
private Mock<IRTWRepository> repository;
private Mock<IModelFactory> factory;
private Mock<IRTWAPIIdentityService> identityService;
List<MaterialAccepted> materials;
MaterialAccepted material;
[TestInitialize]
public void Initialize()
{
repository = new Mock<IRTWRepository>();
factory = new Mock<IModelFactory>();
identityService = new Mock<IRTWAPIIdentityService>();
controller = new MaterialsController(repository.Object);
material = new MaterialAccepted()
{
business = true,
businessService = EnumRecycleCenterService.Dropoff,
residential = false,
residentialService = EnumRecycleCenterService.Pickup,
note = "this a note",
Category = new Category()
{
name = "Books"
}
};
materials = new List<MaterialAccepted>()
{
new MaterialAccepted() { business=true,businessService=EnumRecycleCenterService.Dropoff,residential=false,residentialService=EnumRecycleCenterService.Pickup,note="this a note"},
new MaterialAccepted() { business=false,businessService=EnumRecycleCenterService.Dropoff,residential=true,residentialService=EnumRecycleCenterService.Pickup,note="this a note"},
};
}
[TestMethod]
public void Post_ShouldReturnBadRequestWhenMaterialAcceptedModelValidationFails()
{
//arrange
repository.Setup(r => r.RecycleCenterRepository.Get(3)).Returns(() => new RecycleCenter());
controller.ModelState.AddModelError("error", "unit test error");
//act
var actionResult = controller.Post(2, new MaterialAcceptedModel());
Assert.IsInstanceOfType(actionResult, typeof(BadRequestResult));
}
}
}
Here is the action in the Controller I'm trying to test
[HttpPost]
[Route("api/recyclecenters/{rcid}/materials/")]
public IHttpActionResult Post(int rcid, [FromBody]MaterialAcceptedModel model)
{
try
{
if (model != null)
{
var recycleCenter = TheRepository.RecycleCenterRepository.Get(rcid);
if (recycleCenter == null)
return NotFound();
if (!ModelState.IsValid)
return BadRequest(ModelState);
var entity = TheModelFactory.Parse(model);
if (entity == null) return BadRequest("Could not read material accepted in body");
if (TheRepository.MaterialAcceptedRepository.Get(recycleCenter.RecycleCenterId, entity.Category.name) != null)
return Conflict();
recycleCenter.Materials.Add(entity);
if (TheRepository.SaveAll())
{
string locationHeader = Url.Link("Materials", new { rcid = rcid, name = model.category.ToLower() });
return Created<MaterialAcceptedModel>(locationHeader, TheModelFactory.Create(entity));
}
return BadRequest("Could not save to the database");
}
return BadRequest();
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
If I run this test it will fail because it returns an instancy type of NotFoundResult instead of a BadRequestResult, and this is happening because the test method stops in this line
if (recycleCenter == null)
return NotFound();
But this test it suppose to stop on this line
if (!ModelState.IsValid)
return BadRequest(ModelState);
Any ideas why this
repository.Setup(r => r.RecycleCenterRepository.Get(3)).Returns(() => new RecycleCenter());
is returning null when it should return a new RecycleCenter
It seems like you are setting up the repository mock for rcid = 3, and calling the repository in the controller with rcid = 2.
//arrange
repository.Setup(r => r.RecycleCenterRepository.Get(3)).Returns(() => new RecycleCenter());
controller.ModelState.AddModelError("error", "unit test error");
//act
var actionResult = controller.Post(2, new MaterialAcceptedModel());
Try calling it with rcid = 3
var actionResult = controller.Post(3, new MaterialAcceptedModel());
or change the Moq setup parameter to It.IsAny<int>()
I recently started learning Unit Test in MVC and used NUnit Framework for Test Cases. My problem is, i cannot understand for what should i write Test case. Imagine i have CRUD operation and i want to Test them, so what should be my Test case condition.
Here is my Interface class:
public interface IUserRepository
{
//Creating Single User Records into database using EF.
bool CreateUser(tbl_Users objUser);
//Updating Single User Records into database using EF.
void UpdateUser(tbl_Users objUser);
//Deleting Single User Records from database using EF.
bool DeleteUser(long IdUser);
}
Here is my Repository Class:
public class UserRepository : IUserRepository
{
DBContext objDBContext = new DBContext();
/// <summary>
/// Creating new User Record into Database
/// </summary>
/// <param name="objUser"></param>
public bool CreateUser(tbl_Users objUser)
{
bool blnResult = false;
objUser.MiddleName = string.IsNullOrEmpty(objUser.MiddleName) ? string.Empty : objUser.MiddleName.Trim();
objUser.Photo = string.Empty;
objUser.Approved = false;
objUser.CreatedDate = DateTime.Now;
objUser.DeleteFlag = false;
objUser.UpdBy = 0;
objUser.UpdDate = DateTime.Now;
objDBContext.tbl_Users.Add(objUser);
blnResult = Convert.ToBoolean(objDBContext.SaveChanges());
return blnResult;
}
/// <summary>
/// Updating existing User Record into Database
/// </summary>
/// <param name="objUser"></param>
public void UpdateUser(tbl_Users objUser)
{
objUser.MiddleName = string.IsNullOrEmpty(objUser.MiddleName) ? string.Empty : objUser.MiddleName.Trim();
objUser.Approved = true;
objUser.UpdBy = objUser.IdUser;
objUser.UpdDate = DateTime.Now;
objDBContext.Entry(objUser).State = EntityState.Modified;
objDBContext.SaveChanges();
}
/// <summary>
/// Deleting existing User Record from Database
/// </summary>
/// <param name="IdUser"></param>
public bool DeleteUser(long IdUser)
{
bool blnResult = false;
tbl_Users objUser = objDBContext.tbl_Users.Where(x => x.IdUser == IdUser).Single();
objUser.ConfirmPassword = objUser.Password;
objUser.UpdDate = DateTime.Now;
objUser.DeleteFlag = true;
blnResult = Convert.ToBoolean(objDBContext.SaveChanges());
return blnResult;
}
}
And Here is My Controller class
public class UserController : Controller
{
tbl_Users objUser = new tbl_Users();
UserRepository Repository = new UserRepository();
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult Create(tbl_Users objUser)
{
if (ModelState.IsValid)
{
try
{
Repository.CreateUser(objUser);
return RedirectToAction("Update", "User");
}
catch
{
return View();
}
}
return View();
}
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult Update(tbl_Users objUser)
{
Repository.UpdateUser(objUser);
return View();
}
public ActionResult Delete(long IdUser = 0)
{
bool blnResult = Repository.DeleteUser(IdUser);
if (blnResult)
{
return View("Delete");
}
else
{
return View();
}
}
}
Here are Test cases which i tried to Execute using Moq
[TestFixture]
public class UserControllerTest
{
UserController Controller;
[SetUp]
public void Initialise()
{
Controller = new UserController();
}
[Test]
public void DeleteTest()
{
var ObjUser = new Mock<IUserRepository>();
ObjUser.Setup(X => X.DeleteUser(It.IsAny<long>())).Returns(true);
var Result = ObjUser.Object.DeleteUser(1);
Assert.That(Result, Is.True);
}
[Test]
public void CreateTest()
{
tbl_Users User = new tbl_Users();
Mock<IUserRepository> MockIUserRepository = new Mock<IUserRepository>();
MockIUserRepository.Setup(X => X.CreateUser(It.IsAny<tbl_Users>())).Returns(true);
var Result = MockIUserRepository.Object.CreateUser(User);
Assert.That(Result, Is.True);
}
[TearDown]
public void DeInitialise()
{
Controller = null;
}
}
Can anyone tell me, how to Write test cases for above Controller Action Method with brief description about test cases using Moq.
you have a couple of problems. the first is that you have not tested your controller, you have tested your mock. The second is that your controller creates it's own user repository. this means that you can't provide a mock user repository in order to test, even if you were testing it.
The solution to the first on is to test the controller, by calling its methods and asserting the results, however you'll have solve the second one before you can do that in your tests.
To solve the second one you'll need to apply the dependency inversion principal and pass your IUserRepository implementation into your controller (via the constructor ideally).
you could change your controller to have a constructor like this:
public class UserController : Controller
{
tbl_Users objUser = new tbl_Users();
IUserRepository Repository;
public UserController(IUserRepository userRepository)
{
Repository = userRepository;
}
...etc
}
then you can change your tests to be more like this:
[TestFixture]
public class UserControllerTest
{
[Test]
public void DeleteTest()
{
var ObjUser = new Mock<IUserRepository>();
ObjUser.Setup(X => X.DeleteUser(It.IsAny<long>())).Returns(true);
var Result = new UserController(ObjUser.Object).Delete(1);
Assert.That(Result, //is expected view result with expected model);
Assert.That(ObjUser.Verify(), Is.True);
}
[Test]
public void CreateTest()
{
tbl_Users User = new tbl_Users();
Mock<IUserRepository> MockIUserRepository = new Mock<IUserRepository>();
MockIUserRepository.Setup(X => X.CreateUser(It.IsAny<tbl_Users>())).Returns(true);
var Result = var Result = new UserController(ObjUser.Object).Create(User);;
Assert.That(Result, //is a view result with expected view model);
Assert.That(ObjUser.Verify(), Is.True);
}
}
now you are testing the actual controller and checking it returns the right view and that it interacts with the mock repository in the expected way
I am running a unit test of my PostMyModel route. However, within PostMyModel() I used the line Validate<MyModel>(model) to revalidate my model after it is changed. I am using a test context, so as not to be dependent on the db for the unit tests. I have posted the test context and post method below:
Test Context
class TestAppContext : APIContextInterface
{
public DbSet<MyModel> MyModel { get; set; }
public TestAppContext()
{
this.MyModels = new TestMyModelDbSet();
}
public int SaveChanges(){
return 0;
}
public void MarkAsModified(Object item) {
}
public void Dispose() { }
}
Post Method
[Route(""), ResponseType(typeof(MyModel))]
public IHttpActionResult PostMyModel(MyModel model)
{
//Save model in DB
model.status = "Waiting";
ModelState.Clear();
Validate<MyModel>(model);
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.MyModels.Add(model);
try
{
db.SaveChanges();
}
catch (DbUpdateException)
{
if (MyModelExists(model.id))
{
return Conflict();
}
else
{
throw;
}
}
return CreatedAtRoute("DisplayMyModel", new { id = model.id }, model);
}
When the Validate<MyModel>(model) line runs, I get the error :
System.InvalidOperationException: ApiController.Configuration must not be null.
How can I correct this?
In order for the Validate command to run, there must be mock HttpRequest associated with the controller. The code to do this is below. This will mock a default HttpRequest, which is fairly unused in this case, allowing the method to be unit tested.
HttpConfiguration configuration = new HttpConfiguration();
HttpRequestMessage request = new HttpRequestMessage();
controller.Request = request;
controller.Request.Properties["MS_HttpConfiguration"] = configuration;