MVC Controller test using MOq - asp.net-mvc

I want to test the given method using Moq. How do I make my controller use moq objects? New objects are being created inside the controller method. One of the class is datacontext and other one is also a concrete class. Facing trouble in creating a mock for these classes alslo.
//My Controller class action method
public ActionResult GetRelatedCourses(int stuId)
{
if (Request.Cookies["RememberUsername"] != null)
{
if (System.Web.HttpContext.Current.Cache.Get(userName) == null)
{
CacheUtil.UpdateCache(userName);
}
Dictionary<string, int> sectionsCourses = (Dictionary<string, int>)System.Web.HttpContext.Current.Cache.Get(userName);
if (sectionsForums.ContainsValue(stuId))
{
var contextWrapper = new DataContextWrapper(dataContext);
var courseRepository = new CourseRepository(contextWrapper);
bool Student_Exists = StudentExists(stuId);
if (Student_Exists)
{
IEnumerable<Course> course = courseRepository.GetRelatedCourses(stuId);
var UserProfiles = contextWrapper.dataContext.usp_GetUserProfilesByStudentID(stuId).ToList();
ViewBag.UserProfiles = UserProfiles;
if (course.Count() == 0)
{
ViewBag.ErrorMessage = "No courses available.";
}
return View(courses);
}
return View("NoStudentExists");
}
}
return View("NoAccess");
}

You need to use Dependency Injection and a good IoC like Ninject. Instantiating data objects inside your methods is a no go if you want unit tests.

Related

Simple getter logic in ViewModels

Is it ok to have simple logic (without any dependencies) in ViewModels getters or it should contain just automatic properties? in this case just checking for null so I don't have to do that in controller each time I am using this ViewModel. TicketSearchParameters is a simple model containing string and date properties, there is no Repository or any other dependencies.
public class MyViewModel
{
private TicketSearchParameters _searchParams;
public TicketSearchParameters SearchParams
{
get
{
if (_searchParams == null)
{
_searchParams = new TicketSearchParameters();
_searchParams.CreatedFrom = DateTime.Now.AddDays(-7);
_searchParams.CreatedTo = DateTime.Now;
}
return _searchParams;
}
set
{
_searchParams = value;
}
}
/*** other properties ***/
}
You code is fairly ok. But you can use NULL Object Design Pattern to check null and create NullObject.
make a class named NullSearchParams inherited from SearchParams and initialize it when needed.
You can see Null design pattern documentation here.
https://sourcemaking.com/design_patterns/null_object

Testing a MVC Controller fails with NULL reference exception

Below is the setup that I am trying to test.
The controller:
public ActionResult UpsertStudent(StudentModel studentModel)
{
try
{
if (!CheckStudentUpdateForEdit(studentModel))
{
return Json(new { result = STUDENT_EXISTS });
}
// remaining code removed for brevity
}
private bool CheckStudentUpdateForEdit(StudentModel studentModel)
{
var returnVal = true;
var existingStudent = _updateStudentManager.GetStudentInfo(studentModel.Id);
if (existingStudent.StudentType == "Day Scholar")
{
returnVal = true;
}
else
{
returnVal = false;
}
return returnVal;
}
The Test method:
public void AllowStudentUpdates_Success()
{
var studentModel = new StudentModel()
{
StudentName = "Joe",
Id = "123",
StudentType = "Day Scholar"
};
var studentToAdd = new Student()
{
Id = "123",
Name = "Joe",
StartDate = DateTime.UtcNow.ToShortDateString(),
StudentType = "Day Scholar",
EndDate = "08/10/2016"
};
_studentRulesHelper.Setup(x => x.GetStudentRule(studentModel, true)).Returns(studentToAdd);
_productRulesHelper.Setup(x => x.ReturnStudentRule(studentModel, true)).Returns(studentToAdd);
var res = _controller.UpsertStudent(studentModel) as JsonResult;
if (res != null) Assert.AreEqual("{ result = True }", res.Data.ToString());
}
When it hits the UpsertDoc call, it goes to the actual call in the controller and tries to execute CheckStudentUpdateForEdit() the GetStudentInfo() tries to get an object from the db and returns a null object as there is no student with the id that's passed from the test method.
The test then fails with Null Reference exception.
Now the system under test is not supposed to hit the db. I don't know why this is doing the other way!
Anyone else writing this test will also try to pass a dummy object which is bound to fail at GetStudentInfo() the way the test is setup now.
What do I do to make this work?
I am not sure if I have understood you problem correctly, but looking at the code snippets provided, the test will go and hit the database, because the mock object and its expectation is not defined.
I would have implemented the solution like this -
I am making some assumptions that your _updateStudentManager object is for the class that is doing the DB interaction for Student. I'll call it say StudentRepository. And to allow you to mock the behavior I would make it Interface driven.
So typically my setup would look like this -
//Interface
public interface IStudentrepository
{
StudentModel GetStudentInfo(int studentId);
}
//Class implementing IStudentrepository
public class StudentRepository : IStudentrepository
{
public StudentModel GetStudentInfo(int studentId)
{
//Implementation goes here
}
}
Now in my controller, I would have an instance of IStudentrepository, which can be injected via constructor.
public class StudentController
{
private readonly IStudentrepository updateStudentManager;
public StudentController(IStudentrepository updateStudentManager)
{
this.updateStudentManager = updateStudentManager;
}
}
//Rest of the code for controller....
Now while writing my Test, I will create a mock object of IStudentrepository, define the expectation for the mock object, and inject it when creating the controller object. Something like this.
[TestMethod]
public void TestMethod1()
{
//--Arrange--
//Define a mock object for student repository
var mock = new Mock<IStudentrepository>();
//Define the expectations of the mock object
mock.Setup(s => s.GetStudentInfo(It.IsAny<int>()))
.Returns(new StudentModel {/*return the required object */ });
//Instantiate controller and inject the mock object
StudentController _controller = new StudentController(mock.Object);
//--Act--
var res = _controller.UpsertStudent(studentModel) as JsonResult;
//--Assert--
if (res != null) Assert.AreEqual("{ result = True }", res.Data.ToString());
}
Now when your test method calls the GetStudentInfo method, instead of hitting the db, it will return the value as set in mock object.
This is just a high level implementation, and of course you can modify it as per your design. Hope it helps

Using statements in a web api

I found this code here
using (var objCtx = new SchoolDBEntities())
{
var schoolCourse = from cs in objCtx.Courses
where cs.CourseName == "Course1"
select cs;
Course mathCourse = schoolCourse.FirstOrDefault<Course>();
IList<Course> courseList = schoolCourse.ToList<Course>();
string courseName = mathCourse.CourseName;
}
And I am using it in a Get method of a web api. When i use a using statement I get the following error
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection
I I do not use it, then how would I dispose of the context object responsibly?
I use something like this to solve the problem without resorting to eager loading (in fact usually in a generic abstract base controller that I extend, but this example is simplified):
public class MyController : ApiController
{
private SchoolDBEntities _objCtx;
// Singleton ObjectContext
protected SchoolDBEntities objCtx
{
if(_objCtx == null) _objCtx = new SchoolDBEntities();
return _objCtx;
}
// Use singleton objCtx without using wrapper here, in Get() or other methods.
public String Get()
{
var schoolCourse = from cs in objCtx.Courses
where cs.CourseName == "Course1"
select cs;
Course mathCourse = schoolCourse.FirstOrDefault<Course>();
string courseName = mathCourse.CourseName;
return courseName
}
// ApiController implements IDisposable, so you can override Dispose to do clean-up here.
// This is not called until the controller is disposed, so you won't get the error you report.
protected override void Dispose(Boolean disposing)
{
if (_objCtx!= null)
{
_objCtx.Dispose();
_objCtx = null;
}
base.Dispose(disposing);
}
}

Moq Automapper service in testmethod returns null while mapping

I'm building a website in MVC 4 & using Automapper to map from domain objects to Viewmodel objects. I have injected Automapper as stated here http://rical.blogspot.in/2012/06/mocking-automapper-in-unit-testing.html
and it's working fine inside action methods while debugging, but during unit testing the action method when I inject automapper service I find that service.map is returning null. But while debugging the mapping is fine. I'm not being able to find the reason, trying for over 4 hrs. I have a domain class called Interview & its corrosponding viewmodel as InterviewModel. I have initialized mapping as CreateMap(); in automapper profile config, that has been called from global startup method. Below is the controller & action...
public class NewsAndViewsController : Controller
{
private IInterviewRepository repository;
private IMappingService mappingService;
public NewsAndViewsController(IInterviewRepository productRepository, IMappingService autoMapperMappingService)
{
repository = productRepository;
mappingService = autoMapperMappingService;
}
[HttpPost, ValidateAntiForgeryToken]
[UserId]
public ActionResult Edit(InterviewModel interView, string userId)
{
if (ModelState.IsValid)
{
var interView1 = mappingService.Map<InterviewModel, Interview>(interView);
**// THE ABOVE LINE RETURNING NULL WHILE RUNNING THE BELOW TEST, BUT NOT DURING DEBUGGING**
repository.SaveInterview(interView1);
TempData["message"] = string.Format("{0} has been saved", interView.Interviewee);
return RedirectToAction("Create");
}
return View(interView);
}
}
[TestMethod]
public void AddInterview()
{
// Arrange
var interviewRepository = new Mock<IInterviewRepository>();
var mappingService = new Mock<IMappingService>();
var im = new InterviewModel { Interviewee="sanjay", Interviewer="sanjay", Content="abc" };
mappingService.Setup(m => m.Map<Interview, InterviewModel>(It.IsAny<Interview>())).Returns(im);
var controller = new NewsAndViewsController(interviewRepository.Object, mappingService.Object);
// Act
var result = controller.Edit(im, "2") as ViewResult;
// Assert - check the method result type
Assert.IsNotInstanceOfType(result, typeof(ViewResult));
}
In your test you've got your Interview and InterviewModel classes crossed up in the mappingService.Setup() call (as an aside, I think you could use better naming conventions, or don't use var, to keep your objects clear - "im", "interview" and "interview1" don't make it easy to follow which is the model and which is the view object).
Try this:
[TestMethod]
public void AddInterview()
{
// Arrange
var interviewRepository = new Mock<IInterviewRepository>();
var mappingService = new Mock<IMappingService>();
var interview = new Interview();
var im = new InterviewModel { Interviewee="sanjay", Interviewer="sanjay", Content="abc" };
mappingService.Setup(m => m.Map<InterviewModel, Interview>(im).Returns(interview);
var controller = new NewsAndViewsController(interviewRepository.Object, mappingService.Object);
// Act
var result = controller.Edit(im, "2") as ViewResult;
// Assert - check the method result type
Assert.IsNotInstanceOfType(result, typeof(ViewResult));
}

asp.net mvc - How to create fake test objects quickly and efficiently

I'm currently testing the controller in my mvc app and I'm creating a fake repository for testing. However I seem to be writing more code and spending more time for the fakes than I do on the actual repositories. Is this right?
The code I have is as follows:
Controller
public partial class SomeController : Controller
{
IRepository repository;
public SomeController(IRepository rep)
{
repository = rep;
}
public virtaul ActionResult Index()
{
// Some logic
var model = repository.GetSomething();
return View(model);
}
}
IRepository
public interface IRepository
{
Something GetSomething();
}
Fake Repository
public class FakeRepository : IRepository
{
private List<Something> somethingList;
public FakeRepository(List<Something> somethings)
{
somthingList = somthings;
}
public Something GetSomething()
{
return somethingList;
}
}
Fake Data
class FakeSomethingData
{
public static List<Something> CreateSomethingData()
{
var somethings = new List<Something>();
for (int i = 0; i < 100; i++)
{
somethings.Add(new Something
{
value1 = String.Format("value{0}", i),
value2 = String.Format("value{0}", i),
value3 = String.Format("value{0}", i)
});
}
return somethings;
}
}
Actual Test
[TestClass]
public class SomethingControllerTest
{
SomethingController CreateSomethingController()
{
var testData = FakeSomethingData.CreateSomethingData();
var repository = new FakeSomethingRepository(testData);
SomethingController controller = new SomethingController(repository);
return controller;
}
[TestMethod]
public void SomeTest()
{
// Arrange
var controller = CreateSomethingController();
// Act
// Some test here
// Arrange
}
}
All this seems to be a lot of extra code, especially as I have more than one repository. Is there a more efficient way of doing this? Maybe using mocks?
Thanks
You can mock the repository.
(I use Moq, Mock a database repository using Moq)
As CD proposed, use a mocking framework. I too use Moq, and with Moq your test code could be refactored to something like this:
// Arrange
var repoMock = new Mock<IRepository>();
repoMock.Setup(r => r.GetSomething()).Returns(TestData.SomeThings);
var controller = new SomethingController(repoMock.Object);
// Act
controller.DoStuff();
// Assert
...
I usually find it convenient to put all my test data in a separate TestData class with static properties for everything - that way I know that I test with the same data in each test. This is what you need in TestData for this example:
public static List<Something> SomeThings
{
get
{
var somethings = new List<Something>();
for (int i = 0; i < 100; i++)
{
somethings.Add(new Something
{
value1 = String.Format("value{0}", i),
value2 = String.Format("value{0}", i),
value3 = String.Format("value{0}", i)
});
}
return somethings;
}
}
The better way is using Dev Magic Fake, so you can Mock the database and can be permanent too, you can also Mock the UI
Just add a reference to DevMagicFake.dll
And you can code the following:
[HttpPost]
public ActionResult Create(VendorForm vendorForm)
{
var repoistory = new FakeRepository<VendorForm>();
repoistory.Save(vendorForm);
return View("Page", repoistory.GetAll());
}
This will save the VendorForm permanent in the memory, and you can retrieve it anytime
You can also generate data for this object or any other object in your model, for more information about Dev Magic Fake see the following Link on CodePlex:
http://devmagicfake.codeplex.com
Thanks
M.Radwan

Resources