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

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

Related

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

Autofac Automocking in ASP.NET MVC

So I'm trying to use Autofac Automocking in ASP.NET MVC 5, but for some reason I can't get it to work.
Here's the test so far:
using (var mock = AutoMock.GetLoose())
{
const string mainUserID = "MainUserID";
const string otherUserID = "OtherUserID";
ApplicationUser user = new ApplicationUser()
{
Id = mainUserID,
UserName = "TestUser"
};
var dataProvider = mock.Mock<IDataProtectionProvider>();
dataProvider.DefaultValue = DefaultValue.Mock;
var userManagerMock = mock.Mock<ApplicationUserManager>();
}
The test fails when mocking the ApplicationUserManager. The error is this:
Result StackTrace:
at Autofac.Extras.Moq.AutoMock.Mock[T](Parameter[] parameters)
at AwenterWeb_NUnit.AccountControllerTest.<Deactivate_User>d__0.MoveNext() in C:\Users\Fabis\Documents\Docs\Kvalifikācijas darbs 2015\AwenterWeb\AwenterWeb-NUnit\AccountControllerTest.cs:line 51
at NUnit.Framework.AsyncInvocationRegion.AsyncTaskInvocationRegion.WaitForPendingOperationsToComplete(Object invocationResult)
at NUnit.Core.NUnitAsyncTestMethod.RunTestMethod()
Result Message: System.InvalidCastException : Unable to cast object of type 'AwenterWeb.ApplicationUserManager' to type 'Moq.IMocked`1[AwenterWeb.ApplicationUserManager]'.
The same thing happens when trying to automock the ApplicationDbContext and it has a very simple constructor, so there shouldn't even be any issues with it.
I'm new to Mocking - what should I do in this scenario?
Edit: Also kind of an unrelated question, maybe you guys know - I've noticed that when creating a Moq for a DbSet using a list created previously in the test, I have to do this:
var dbSetMock = new Mock<IDbSet<DbEntity>>();
dbSetMock.Setup(m => m.Provider).Returns(data.Provider);
dbSetMock.Setup(m => m.Expression).Returns(data.Expression);
dbSetMock.Setup(m => m.ElementType).Returns(data.ElementType);
dbSetMock.Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
It seems really unintuitive. Is there a way to just tell the mock to take the list? So something like:
dbSetMock.Setup(m => m).Returns(data);
Or any other way to create a DbSet Moq from an existing list quickly without having to write those 4 extra lines?
If you look at ligne 73 of MoqRegistrationHandler.cs you can see that only interface is moqable using Autofac.Extras.Moq
var typedService = service as TypedService;
if (typedService == null ||
!typedService.ServiceType.IsInterface ||
typedService.ServiceType.IsGenericType && typedService.ServiceType.GetGenericTypeDefinition() == typeof(IEnumerable<>) ||
typedService.ServiceType.IsArray ||
typeof(IStartable).IsAssignableFrom(typedService.ServiceType))
return Enumerable.Empty<IComponentRegistration>();
var rb = RegistrationBuilder.ForDelegate((c, p) => CreateMock(c, typedService))
.As(service)
.InstancePerLifetimeScope();
You can change the code but it may be quite difficult to make it works with non parameter less dependency.
Can your dependencies be changed to use an interface instead of a concrete class ? if it is not possible and/or if it doesn't make sense, you can use the MockRepository to create your non parameter-less component and then inject it on the AutoMock class.
class Program
{
static void Main(string[] args)
{
using (var mock = AutoMock.GetLoose())
{
/// configure your non interface component with constructor parameters
/// if foo need more complex parameters you can get them
/// using mock.Mock<T>().Object
var fooMock = mock.MockRepository.Create<Foo>((String)null);
fooMock.SetupGet(f => f.Value).Returns("test");
// insert your instance into the container
mock.Provide<Foo>(fooMock.Object);
var bar = mock.Create<Bar>();
Console.WriteLine(bar.GetValue());
}
}
}
public class Foo
{
public Foo(String value)
{
this._value = value;
}
private readonly String _value;
public virtual String Value
{
get
{
return this._value;
}
}
}
public interface IBar
{
String GetValue();
}
public class Bar : IBar
{
public Bar(Foo foo)
{
this._foo = foo;
}
private readonly Foo _foo;
public String GetValue()
{
return this._foo.Value;
}
}
It is not a perfect solution but without big refactoring of the Autofac.Extras.Moq project I can't see any simpler way to do it.

MVC Controller test using MOq

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.

Unit testing a MVC controller

I'm trying to figure out the best way to build my unit tests for an MVC app. I created a simple model and interface, which is used by the controller constructors so that the testing framework (Nsubstitute) can pass a mocked version of the repository. This test passes, as expected.
My problem is now I want to take this a step further and test the file I/O operations in the "real" instantiation of IHomeRepository. This implementation should read a value from a file in the App_Data directory.
I've tried building a test without passing a mocked version of IHomeRepsotory in, however HttpContext.Current is null when I run my test.
Do I need to mock HttpContext? Am I even going about this in the right way?
//The model
public class VersionModel
{
public String BuildNumber { get; set; }
}
//Interface defining the repository
public interface IHomeRepository
{
VersionModel Version { get; }
}
//define the controller so the unit testing framework can pass in a mocked reposiotry. The default constructor creates a real repository
public class HomeController : Controller
{
public IHomeRepository HomeRepository;
public HomeController()
{
HomeRepository = new HomeRepoRepository();
}
public HomeController(IHomeRepository homeRepository)
{
HomeRepository = homeRepository;
}
.
.
.
}
class HomeRepoRepository : IHomeRepository
{
private VersionModel _version;
VersionModel IHomeRepository.Version
{
get
{
if (_version == null)
{
var absoluteFileLocation = HttpContext.Current.Server.MapPath("~/App_Data/repo.txt");
if (absoluteFileLocation != null)
{
_version = new VersionModel() //read the values from file (not shown here)
{
BuildNumber = "value from file",
};
}
else
{
throw new Exception("path is null");
}
}
return _version;
}
}
}
[Fact]
public void Version()
{
// Arrange
var repo = Substitute.For<IHomeRepository>(); //using Nsubstitute, but could be any mock framework
repo.Version.Returns(new VersionModel
{
BuildNumber = "1.2.3.4",
});
HomeController controller = new HomeController(repo); //pass in the mocked repository
// Act
ViewResult result = controller.Version() as ViewResult;
var m = (VersionModel)result.Model;
// Assert
Assert.True(!string.IsNullOrEmpty(m.Changeset));
}
I believe you want test the real instantiation of IHomeRepository, which connects to a real database. In that case you need an App.config file, which specify the connection string. This is not a Unit test and it would an Integration Test. With HttpContext being null, you still can fake the HttpContext, retrieve real data from the database. See also here.

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

Resources