I'm trying to test my project. I have never used tests before and I am starting to learn I would like a help, in the simplest case I want test this public ActionResult Index() but I don't know how to Inject those dependencies.
Controller:
Controller:
public class WorkPlacesController : Controller
{
private readonly IWorkPlaceService workPlaceService;
public WorkPlacesController(IWorkPlaceService workPlaceService)
{
this.workPlaceService = workPlaceService;
}
// GET: WorkPlaces
public ActionResult Index()
{
var workPlaces = workPlaceService.GetWorkPlaces(includedRelated:
true);
return View(workPlaces);
}
}
Here is my Service
Service
public class WorkPlaceService : IWorkPlaceService
{
private readonly IWorkPlaceRepository workPlacesRepository;
private readonly IUnitOfWork unitOfWork;
public WorkPlaceService(IWorkPlaceRepository workPlacesRepository, IUnitOfWork unitOfWork)
{
this.workPlacesRepository = workPlacesRepository;
this.unitOfWork = unitOfWork;
}
}
public interface IWorkPlaceService
{
IEnumerable<WorkPlace> GetWorkPlaces(string workPlaceDescription = null, bool includedRelated = true);
}
And my Repository
Repository
public class WorkPlaceRepository : RepositoryBase<WorkPlace>, IWorkPlaceRepository
{
public WorkPlaceRepository(IDbFactory dbFactory)
: base(dbFactory) { }
public WorkPlace GetWorkPlaceByDescription(string workPlaceDescription)
{
var workPlace = this.DbContext.WorkPlaces.Where(c => c.Description == workPlaceDescription).FirstOrDefault();
return workPlace;
}
}
public interface IWorkPlaceRepository : IRepository<WorkPlace>
{
WorkPlace GetWorkPlaceByDescription(string workPlaceDescription);
}
Factory
public class DbFactory : Disposable, IDbFactory
{
AgendaEntities dbContext;
public AgendaEntities Init()
{
return dbContext ?? (dbContext = new AgendaEntities());
}
protected override void DisposeCore()
{
if (dbContext != null)
dbContext.Dispose();
}
}
I tried to do something like this:
public void BasicIndexTest()
{
// Arrange
var mockRepository = new Mock<IWorkPlaceService>();
var controller = new WorkPlacesController(mockRepository.Object);
// Act
ActionResult actionResult = controller.Index() as ViewResult;
// Assert
Assert.IsInstanceOfType(actionResult, typeof(List<WorkPlace>));
}
How do I inject in this controller the data needed to go in the database and bring the results?
I Want test this public ActionResult Index() but I don't know how to Inject those dependencies.
Mock the behavior of required dependencies of the controller for the test and assert the desired behavior when the test is exercised.
For example, based on what you have done so far
public void BasicIndexTest() {
// Arrange
var mockService = new Mock<IWorkPlaceService>();
var workPlaces = new List<WorkPlace>() {
new WorkPlace()
};
mockService
.Setup(_ => _.GetWorkPlaces(It.IsAny<string>(), It.IsAny<bool>()))
.Returns(workPlaces);
var controller = new WorkPlacesController(mockService.Object);
// Act
var actionResult = controller.Index() as ViewResult;
// Assert
Assert.IsNotNull(actionResult);
var model = actionResult.Model;
Assert.IsNotNull(model)
Assert.IsInstanceOfType(model, typeof(List<WorkPlace>));
Assert.AreEqual(workPlaces, model);
}
Only the IWorkPlaceService was needed for the testing of Index action, but fake data was needed for the invocation of the GetWorkPlaces method. So the mock was configured to return a list of objects when called and pass it to the view result.
Related
I am needing to set up a Unit Test for our project. In our Controllers we are using a Unit of Work which holds all the repositories and calling the repository in our IHttpActionResult to get the data.
So far I have set up a Mock of the Interfaces and this is calling the correct IHttpActionResult in the Controller but there is no data coming back.
[TestMethod]
public void TestMethod1()
{
var unitOfWork = new Mock<IUnitOfWork>();
var repo = new Mock<IAuditReleaseRepository>();
unitOfWork.Setup(e => e.AuditReleaseRepository).Returns(repo.Object);
var auditReleaseController = new AuditReleaseController(unitOfWork.Object);
var result = auditReleaseController.Get() as ViewResult;
var model = result.ViewData.Model as IQueryable<AuditReleas>;
Assert.AreEqual(12, model.Count());
}
public class AuditReleaseController : BaseController
{
private IAuditReleaseRepository _auditReleaseRepository;
private IUnitOfWork _unitOfWork;
public AuditReleaseController(IUnitOfWork unitOfWork)
{
this._unitOfWork = unitOfWork;
this._auditReleaseRepository = unitOfWork.AuditReleaseRepository;
}
[HttpGet, Route("audit-releases")]
public IHttpActionResult Get()
{
var query = this._auditReleaseRepository.GetAll();
return Ok(query);
}
}
public class AuditReleaseRepository : RepositoryBase<AuditReleas>, IAuditReleaseRepository
{
private readonly RetailAssignmentEntities _entities;
public AuditReleaseRepository(RetailAssignmentEntities entities) : base(entities)
{
this._entities = entities;
}
IEnumerable<AuditReleaseDto> IDtoRepository<AuditReleaseDto>.GetAll()
{
return base.GetAll().Where(x=>x.IsReleaseEnabled).Select(AuditReleaseMapping.All).OrderByDescending(x => x.Id);
}
}
This is the Mapping that is taking place to get the data in the GetAll method:
public class AuditReleaseMapping
{
public static Expression<Func<AuditReleas, AuditReleaseDto>> All = (auditRelease) => new AuditReleaseDto()
{
EndDate = auditRelease.AuditReleaseEndDate,
Id = auditRelease.AuditReleaseId,
Name = auditRelease.AuditReleaseName,
StartDate = auditRelease.AuditReleaseStartDate,
AuditPeriodId = auditRelease.AuditPeriod.AuditPeriodId,
AuditYearId = auditRelease.AuditPeriod.AuditYear.AuditYearId,
AuditEndDate = auditRelease.AuditPeriod.AuditEndDate,
AuditStartDate = auditRelease.AuditPeriod.AuditStartDate
};
}
What would be ideal is to call the Controller, which would call the repository, which would then call the Mapping but so far it's not even calling the Repository to get the data. I need help getting that functionality set up.
It looks like you need to Setup the behavior for your Mock repo.GetAll(). You will need to create a list of AuditReleaseDto's for your Mocked repo to return. Call it TestAuditReleaseDtos. You can create this TestData in the beginning of your TestMethod or in the TesstClass initialization. Then use it in a line right after creating your Mock:
var repo = new Mock<IAuditReleaseRepository>();
repo.Setup(r => r.GetAll()).Returns(TestAuditReleaseDtos);
unitOfWork.Setup(e => e.AuditReleaseRepository).Returns(repo.Object);
I'm a sitecore developer and I want to create a sample sitecore helix unit testing project for testing out our "HomeBottomContentController" controller:
public class HomeBottomContentController : GlassController
{
private readonly ISitecoreContext _iSitecoreContext;
public HomeBottomContentController(ISitecoreContext iSitecoreContext)
{
_iSitecoreContext = iSitecoreContext;
}
public override ActionResult Index()
{
var model = _iSitecoreContext.GetCurrentItem<Home_Control>();
return View("~/Views/HomeBottomContent/HomeBottomContent.cshtml", model);
}
}
I have created a WTW.Feature.HomeBottomContent.Tests project, for the purpose of testing this entire component using helix unit testing. In it I have a UnitTest1.cs file with following:
namespace WTW.Feature.HomeBottomContent.Tests
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void Test_ISitecoreContextInsertion()
{
var iSitecoreContext = Mock.Of<Glass.Mapper.Sc.ISitecoreContext>();
HomeBottomContentController controllerUnderTest = new HomeBottomContentController(iSitecoreContext);
var result = controllerUnderTest.Index() as ViewResult;
Assert.IsNotNull(result);
}
}
}
This test does pass, meaning "result" is NOT null; however, the problem is when I step into the Index() code, I see that the "model" variable is NULL when we do
var model = _iSitecoreContext.GetCurrentItem<Home_Control>();
My question is, how exactly do I change this code to make sure that the "model" in that line does not become null? How do I "mock" an item in unit test code for the _iSitecoreContext so that it has a "Home_Control" template with legit values for its fields? Would that even be the right approach? Most online sources I've found do not have a similar scenario, I'm looking for the shortest code possible.
Another question I had is, how can I test the below Index() method in my [TestMethod], given that the SitecoreContext is declared inside the Index() method, rather than received in the HomeBottomContentController constructor like above? Is there a way to do that from the [TestMethod], or we have to send in the SitecoreContext into the HomeBottomContentController constructor or into the Index() method as a parameter?
public override ActionResult Index()
{
var context = new SitecoreContext();
var model = context.GetCurrentItem<Home_Control>();
return View("~/Views/HomeBottomContent/HomeBottomContent.cshtml", model);
}
In that case you would need to mock the desired behavior on the mocked dependency
[TestClass]
public class UnitTest1 {
[TestMethod]
public void Test_ISitecoreContextInsertion() {
//Arrange
var model = new Home_Control() {
//...populate as needed
}
var iSitecoreContext = new Mock<Glass.Mapper.Sc.ISitecoreContext>();
//Setup the method to return a model when called.
iSitecoreContext.Setup(_ => _.GetCurrentItem<Home_Control>()).Returns(model);
var controllerUnderTest = new HomeBottomContentController(iSitecoreContext.Object);
//Act
var result = controllerUnderTest.Index() as ViewResult;
//Assert
Assert.IsNotNull(result);
Assert.IsNotNull(result.Model);
//...other assertions.
}
}
UPDATE
Creating the context within the action tightly couples it to the context, making it almost impossible to mock. That is the reason explicit dependencies are injected
You can do something like that:
public class HomeBottomContentController : GlassController
{
private readonly ISitecoreContext _iSitecoreContext;
public HomeBottomContentController(ISitecoreContext iSitecoreContext)
{
_iSitecoreContext = iSitecoreContext;
}
public override ActionResult Index()
{
var model = this.GetCurrentItem();
return View("~/Views/HomeBottomContent/HomeBottomContent.cshtml", model);
}
protected virtual Home_Control GetCurrentItem()
{
return _iSitecoreContext.GetCurrentItem<Home_Control>();
}
}
namespace WTW.Feature.HomeBottomContent.Tests
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void Test_ISitecoreContextInsertion()
{
var iSitecoreContext = Mock.Of<Glass.Mapper.Sc.ISitecoreContext>();
var controllerUnderTest = new FakeHomeBottomContentController(iSitecoreContext);
var result = controllerUnderTest.Index() as ViewResult;
Assert.IsNotNull(result);
}
}
public class FakeHomeBottomContentController : HomeBottomContentController
{
public FakeHomeBottomContentController(ISitecoreContext iSitecoreContext) : base(iSitecoreContext)
{
}
protected override Home_Control GetCurrentItem()
{
// return instance of Home_Control type
// e.g.
return new Home_Control();
}
}
}
I am trying to write a unit test for my existing MVC Web Aplication. In that I am facing some problem in automapper (IMapper) Whenever am using map function it returns null value.
My Controller Code:
public class UserAdministrationController : BaseController
{
private readonly iUserService _userService;
private readonly IMapper _mapper;
public NewsController(iUserService userService, IMapper mapper)
{
_userService = userService;
_mapper = mapper;
}
public ActionResult Create(int CompanyID == 0)
{
UserDetail data = _userService(CompanyID);
var Modeldata = _mapper.Map<UserDetailViewModel, UserDetail>(data);
return View(Modeldata);
}
}
Mock Mapping Code:
public class MappingDataTest : CommonTestData
{
public Mock<IMapper> MappingData()
{
var mappingService = new Mock<IMapper>();
UserDetailViewModel interview = getUserDetailViewModel(); // get value of UserDetailViewModel
UserDetail im = getUserDetail(); // get value of UserDetails
mappingService.Setup(m => m.Map<UserDetail, UserDetailViewModel>(im)).Returns(interview);
mappingService.Setup(m => m.Map<UserDetailViewModel, UserDetail>(interview)).Returns(im);
return mappingService;
}
}
Mocking Code:
[TestClass]
public class UserAdminControllerTest
{
private MappingDataTest _common;
[TestInitialize]
public void TestCommonData()
{
_common = new MappingDataTest();
}
[TestMethod]
public void UserCreate()
{
//Arrange
UserAdministrationController controller = new UserAdministrationController(_common.mockUserService().Object, _common.MappingData().Object);
controller.ControllerContext = _common.GetUserIdentity(controller);
// Act
ViewResult newResult = controller.Create() as ViewResult;
// Assert
Assert.IsNotNull(newResult);
}
}
Mapper is not working its always showing the null value in controller. kindly help me. Thanks in Advance.
I would recommend not mocking AutoMapper. There's not much value in controller unit tests for one, and this is similar to mocking a JSON serializer. Just use the real thing.
You should try the following:
public class MappingDataTest : CommonTestData
{
public Mock<IMapper> MappingData()
{
var mappingService = new Mock<IMapper>();
UserDetail im = getUserDetail(); // get value of UserDetails
mappingService.Setup(m => m.Map<UserDetail, UserDetailViewModel>(It.IsAny<UserDetail>())).Returns(interview); // mapping data
mappingService.Setup(m => m.Map<UserDetailViewModel, UserDetail>(It.IsAny<UserDetailtViewModel>())).Returns(im); // mapping data
return mappingService;
}
}
The thing is, your mock was expecting the exact instance of UserDetailViewModel interview = getUserDetailViewModel(); to setup this mapping, and this is why it was returning null. Null it will be expecting any reference to UserDetailViewModel and for any reference to UserDetailtViewModel it will return the expected mapped instance.
I am trying to test a controller action that accepts a view model and creates a new entry. Here is the controller action:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ContactViewModel viewModel)
{
if (!ModelState.IsValid)
return View("Create", viewModel);
_unitOfWork.Contacts.Add(Mapper.Map(viewModel, new Contact()));
_unitOfWork.Complete();
return RedirectToAction("Index");
}
And the unit test:
[TestClass]
public class ContactControllerTests
{
private ContactsController _controller;
private Mock<IContactRepository> _mockRepository;
private string _userId;
private Mock<IUnitOfWork> _mockUoW;
[ClassInitialize]
public static void Init(TestContext context)
{
Mapper.Initialize(c => c.AddProfile<MappingProfile>());
}
[TestInitialize]
public void TestInitialize()
{
_userId = "1";
_mockRepository = new Mock<IContactRepository>();
_mockUoW = new Mock<IUnitOfWork>();
_mockUoW.SetupGet(u => u.Contacts).Returns(_mockRepository.Object);
_controller = new ContactsController(_mockUoW.Object);
_controller.MockCurrentUser(_userId, "user#domain.com");
}
[TestMethod]
public void CreatePost_ValidValuesSubmitted_ShouldCallComplete()
{
var viewModel = new ContactViewModel()
{
FirstName = "a",
LastName = "b"
};
_controller.Create(viewModel);
_mockRepository.Object.GetContacts(_userId).Should().HaveCount(1);
}
}
The unit test always returns the count 0 while I expect it to be 1. I am pretty new to TDD and I implemented unit of work and repository pattern as shown in Mosh Hamedani's course at:
https://app.pluralsight.com/library/courses/full-stack-dot-net-developer-architecture-testing/table-of-contents
You have not mocked any behavior for the repository in the above example.
Based on provided example, let's assume a simple interface like this.
public interface IContactRepository {
void Add(Contact contact);
IEnumerable<Contact> GetContacts(string _userId);
}
You need to have some form of storage for your data.
[TestInitialize]
public void TestInitialize() {
_userId = "1";
var data = new List<Contact>();//To store test data.
//Configure repository
_mockRepository = new Mock<IContactRepository>();
_mockRepository.Setup(m => m.Add(It.IsAny<Contact>())).Callback<Contact>(data.Add);
_mockRepository.Setup(m => m.GetContacts(_userId)).Returns(data);
//Configure UoW
_mockUoW = new Mock<IUnitOfWork>();
_mockUoW.SetupGet(u => u.Contacts).Returns(_mockRepository.Object);
_controller = new ContactsController(_mockUoW.Object);
_controller.MockCurrentUser(_userId, "user#domain.com");
}
or forego the mock and create a fake.
public class FakeContactRepository : IContactRepository {
private ICollection<Contact> data;
public FakeContactRepository(ICollection<Contact> data) {
this.data = data;
}
public void Add(Contact contact) {
data.Add(contact);
}
public IEnumerable<Contact> GetContacts(string _userId) {
return data;
}
}
and set it up for the test.
[TestInitialize]
public void TestInitialize() {
_userId = "1";
var data = new List<Contact>();//To store test data.
//Configure repository
var fakeRepository = new FakeContactRepository(data);
//Configure UoW
_mockUoW = new Mock<IUnitOfWork>();
_mockUoW.SetupGet(u => u.Contacts).Returns(fakeRepository );
_controller = new ContactsController(_mockUoW.Object);
_controller.MockCurrentUser(_userId, "user#domain.com");
}
I'm trying to Setup a Mock call to a the IModelFactory interface that I have.
here is the IModelFactory interface
public interface IModelFactory
{
MaterialAcceptedModel Create(MaterialAccepted model);
MaterialAccepted Parse(MaterialAcceptedModel model);
}
This is the ModelFactory class which implements the IModelFactor interface (I've only add here the method I'm trying to test, no need to add the implementation of the Create Method)
public class ModelFactory : IModelFactory
{
private UrlHelper _urlHelper;
private IRTWRepository _repo;
//private IKeysGeneratorService _keysGen;
private IGeocodeService _geocoder;
public ModelFactory(HttpRequestMessage request, IRTWRepository repo,IGeocodeService geocoder)
{
_urlHelper = new UrlHelper(request);
_repo = repo;
_geocoder = geocoder;
}
#region Parses
public MaterialAccepted Parse(MaterialAcceptedModel model)
{
try
{
if (!string.IsNullOrWhiteSpace(model.category))
{
var category = _repo.CategoryRepository.Get(model.category);
if (category == null) return null;
var entry = new MaterialAccepted()
{
business = model.business,
businessService = model.businessService,
residential = model.residential,
residentialService = model.residentialService,
note = model.note,
Category = category
};
return entry;
}
return null;
}
catch
{
return null;
}
}
#endregion
}
I'm using a BaseAPiController that contains the repo and configuration Interfaces
public class BaseApiController : ApiController
{
IRTWRepository _repository;
IModelFactory _modelFactory;
IConfiguration _configuration;
IGeocodeService _geocoder;
public BaseApiController(IRTWRepository repository,IConfiguration configuration)
{
_repository = repository;
_configuration = configuration;
}
protected IRTWRepository TheRepository
{
get
{
return _repository;
}
}
protected IConfiguration TheConfiguration
{
get
{
return _configuration;
}
}
protected IModelFactory TheModelFactory
{
get
{
_geocoder = new GeocodeService(_configuration.GetValue("geocodeGoogleApiKey"));
if (_modelFactory == null)
{
_modelFactory = new ModelFactory(this.Request, _repository,_geocoder);
}
return _modelFactory;
}
}
Here is the action method 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);
}
}
This is the line that returns null even though I mocked it up on my test method
var entity = TheModelFactory.Parse(model);
and this one is my TestClass
namespace API.Tests.Web
{
[TestClass]
public class MaterialsControllerTest
{
private Mock<IRTWRepository> repository;
private Mock<IModelFactory> factory;
private Mock<IConfiguration> configuration;
private Mock<IRTWAPIIdentityService> identityService;
private MaterialsController controller;
RecycleCenter recycleCenter;
private MaterialAccepted CreateMaterial()
{
return new MaterialAccepted()
{
business = true,
businessService = EnumRecycleCenterService.Dropoff,
residential = false,
residentialService = EnumRecycleCenterService.Pickup,
note = "this a note",
Category = new Category()
{
name = "Books"
}
};
}
[TestInitialize]
public void Initialize()
{
repository = new Mock<IRTWRepository>();
factory = new Mock<IModelFactory>();
configuration = new Mock<IConfiguration>();
identityService = new Mock<IRTWAPIIdentityService>();
controller = new MaterialsController(repository.Object,configuration.Object);
controller.Request = new HttpRequestMessage();
recycleCenter = new RecycleCenter(){RecycleCenterId = 1};
}
[TestMethod]
public void Post_ShouldReturnConflictIfTheRecycleCenterAlreadyTakesMaterial()
{
//arrange
repository.Setup(r => r.RecycleCenterRepository.Get(It.IsAny<int>())).Returns(() => recycleCenter);
factory.Setup(f => f.Parse(new MaterialAcceptedModel())).Returns(() => new MaterialAccepted());
configuration.Setup(c => c.GetValue(It.IsAny<string>())).Returns(() => "APIKEY");
repository.Setup(r => r.MaterialAcceptedRepository.Get(It.IsAny<int>(), It.IsAny<string>())).Returns(() => null);
//act
var actionResult = controller.Post(It.IsAny<int>(),new MaterialAcceptedModel());
//assert
Assert.IsInstanceOfType(actionResult, typeof(ConflictResult));
}
}
}
This is the line that's not working because it always return null instead of a new instance of MaterialAccepted
factory.Setup(f => f.Parse(new MaterialAcceptedModel())).Returns(() => new MaterialAccepted());
I tried f.Parse(It.IsAny()) but still doesn't work.
To clarify
the above line of code is returning null because is not mocking the f.Parse() call, instead is executing it and returning null because the if condition I have on that method
Anyone could explain why the Setup is not working?
Setting up your Mock using It.IsAny will work:
factory.Setup(f => f.Parse(It.IsAny<MaterialAcceptedModel>()))
.Returns(() => new MaterialAccepted());
However, as has been said by #Macilquham, I can't see where your are passing the Mock to your controller in the supplied code so that it is used by the production code.
If you don't call the method on your Mock object, which you don't, you're currently calling the method on the instance of the real object created by your base class, then it doesn't matter how you set up your mock it's not going to work. If you are able to change your base class, then doing something like this would allow you to work around your problem:
// Add defaulted parameter to base class to allow modelFactory creation
// to be overridden/injected (this will prevent the current default behaviour
// when fetching the factory, if a non-null is passed in)
public BaseApiController(IRTWRepository repository,IConfiguration configuration,
IModelFactory modelFactory = null)
{
_modelFactory = modelFactory;
}
Modify your sut constructor to allow you to supply a modelFactory (again, default it to null), then amend your test as appropriate:
controller = new MaterialsController(repository.Object,configuration.Object,
factory.Object);
You don't seem to be injecting in the IModelFactory into the controller. You need to make sure that your production code is using the Mock you are setting up in the test.
Mock cannot return null directly.
The trick is just to create a null object.
Assuming the object returned is of type class Material:
Material nullMaterial = null;
...
repository.Setup(r => r.MaterialAcceptedRepository
.Get(It.IsAny<int>(), It.IsAny<string>()))
.Returns(nullMaterial);
This should solve your problem