Testing a controllers parameterless constructor - asp.net-mvc

I have a fairly basic HomeController in my application and I wrote a test class for it. After running code coverage analysis on my test class I realized I don't have any test for the default constructor.
This is my HomeController
public class HomeController : BaseController
{
private INewsRepository _newsRepository;
private INewsletterRepository _newsletterRepository;
private string _currentLanguage;
public HomeController()
{
_newsRepository = NewsRepository.Current;
_newsletterRepository = NewsletterRepository.Current;
_currentLanguage = ApplicationConfig.Current.CurrentLanguage;
}
public HomeController(INewsRepository newsRepository, INewsletterRepository newsletterRepository, string currentLanguage)
{
_newsRepository = newsRepository;
_newsletterRepository = newsletterRepository;
_currentLanguage = currentLanguage;
}
public ActionResult Index()
{
return View();
}
public ActionResult LatestNews()
{
return View(_newsRepository.ListAll().Where(n => n.LanguageKey.ToLower() == _currentLanguage.ToLower()).OrderByDescending(n => n.Date).Take(10));
}
public ActionResult LatestNewsletters()
{
return View(_newsletterRepository.ListAll().Where(n => n.LanguageKey.ToLower() == _currentLanguage.ToLower()).OrderByDescending(n => n.Date).Take(10));
}
}
And this is my test class for it:
[TestClass]
public class HomeControllerTest
{
private INewsletterRepository _mockNewsletterRepostiory = null;
private INewsRepository _mockNewsRepostiory = null;
private List<News> _fakeNewsList = new List<News> {
new News{Id = 0, Title = "some title", Date = new DateTime(1989, 2, 19), LanguageKey = "fa", Description = "some description"},
new News{Id = 1, Title = "some title", Date = new DateTime(1989, 2, 20), LanguageKey = "fa", Description = "some description"},
new News{Id = 2, Title = "some title", Date = new DateTime(1989, 2, 21), LanguageKey = "fa", Description = "some description"},
new News{Id = 3, Title = "some title", Date = new DateTime(1989, 2, 22), LanguageKey = "fa", Description = "some description"}
};
private List<Newsletter> _fakeNewsletterList = new List<Newsletter>
{
new Newsletter{ Id = 0, Description = "some description", UrlKey = "first-newsletter", Title = "some title", SendDate = null, NewsletterContents = null, LanguageKey = "fa", Date = new DateTime(1989, 2, 19) },
new Newsletter{ Id = 1, Description = "some description", UrlKey = "first-newsletter", Title = "some title", SendDate = null, NewsletterContents = null, LanguageKey = "fa", Date = new DateTime(1989, 2, 20) },
new Newsletter{ Id = 2, Description = "some description", UrlKey = "first-newsletter", Title = "some title", SendDate = null, NewsletterContents = null, LanguageKey = "fa", Date = new DateTime(1989, 2, 21) },
new Newsletter{ Id = 3, Description = "some description", UrlKey = "first-newsletter", Title = "some title", SendDate = null, NewsletterContents = null, LanguageKey = "fa", Date = new DateTime(1989, 2, 22) }
};
[TestInitialize]
public void Setup()
{
// Mock News Repository
var mockNewsRepository = MockRepository.GenerateStub<INewsRepository>();
mockNewsRepository.Stub(m => m.ListAll()).Return(_fakeNewsList.AsQueryable());
// Mock Newsletter Repository
var mockNewsletterRopository = MockRepository.GenerateStub<INewsletterRepository>();
mockNewsletterRopository.Stub(m => m.ListAll()).Return(_fakeNewsletterList.AsQueryable());
_mockNewsletterRepostiory = mockNewsletterRopository;
_mockNewsRepostiory = mockNewsRepository;
}
[TestMethod]
public void IndexReturnsView()
{
// Arrange
HomeController homeController = new HomeController(_mockNewsRepostiory, _mockNewsletterRepostiory, "fa");
// Act
ViewResult result = homeController.Index() as ViewResult;
// Assert
Assert.AreEqual("", result.ViewName);
}
[TestMethod]
public void LatestNewsReturnsCorrectObject()
{
// Arrange
HomeController homeController = new HomeController(_mockNewsRepostiory, _mockNewsletterRepostiory, "fa");
// Act
ViewResult result = homeController.LatestNews() as ViewResult;
// Assert
Assert.IsNotNull(result.ViewData.Model, "Result model is not null.");
Assert.IsTrue(_fakeNewsList.OrderByDescending(n => n.Date).SequenceEqual(result.ViewData.Model as IQueryable<News>), "Model is correct");
}
[TestMethod]
public void LatestNewslettersReturnsCorrectObject()
{
// Arrange
HomeController homeController = new HomeController(_mockNewsRepostiory, _mockNewsletterRepostiory, "fa");
// Act
ViewResult result = homeController.LatestNewsletters() as ViewResult;
// Assert
Assert.IsNotNull(result.ViewData.Model, "Result model is not null.");
Assert.IsTrue(_fakeNewsletterList.OrderByDescending(n => n.Date).SequenceEqual(result.ViewData.Model as IQueryable<Newsletter>), "Model is correct");
}
}
First of all do I really need to test this constructor?
Secondly, Is it a good practice to make the _newsRepository and the other guys public and readonly then write a test method to check their types after constructing the controller?

The only reason I'd recommend writing a test for the constructor is if you care a lot about getting as much code coverage as possible. Testing the fact that you can create an instance of the controller, and whether instances of each object created in the ctor are valid isn't a very valuable test. I'd say it's a waste of time.
So, for your first question I suggest you don't worry about unit testing the ctor. If there is a problem in the ctor then you will notice it very quickly via other unit tests, as explained in my next comment.
As for making the repository classes public and readonly, I don't recommend doing that. What you really need to focus on, regards unit tests, is functionality of the controller, especially methods that make use of the objects which are created in the ctor. That's where you need to concentrate on. Those tests will tell you whether or not these was an issue in the ctor for those objects.

Related

Trying to test two controller actions that share Session data. MVC

I'm trying to write a Unit test that checks two controller actions. These controller actions rely on Session variables. So far I have this:
Unit Test:
[TestMethod]
public void TableOfContentReportTest()
{
// Arrange
var fakeDb = TestFakes.SetupFakeDbContext();
var controller = TestFakes.ProjectController(fakeDb);
// Act
var selectedSubs = AutoMapper.Mapper.Map<ProjectSubmissionViewModel>(fakeDb.ProjectSubmission.FirstOrDefault());
selectedSubs.Selected = true;
controller.Session["SelectedSubmissions"] = new List<ProjectSubmissionViewModel> {selectedSubs};
var result = controller.SubmissionIndex("ProjectTitle", true,1, 10,"","","","","",
StaticStrings.Report_TableOfContents) as ViewResult;
// Assert
Assert.IsNotNull(result);
var testSession = controller.processReport();
}
TestFakes.ProjectController sets up the session for the controller like this:
//...
var session = new Mock<HttpSessionStateBase>();
var context = new Mock<HttpContextBase>(MockBehavior.Strict);
context.SetupGet(x => x.Session).Returns(session.Object);
var rc = new RequestContext(context.Object, new RouteData());
var controller = new ProjectController(fakeDb);
controller.ControllerContext = new ControllerContext(rc, controller);
//...
SubmissionIndex sets the Session variable:
public virtual ActionResult SubmissionIndex(
string sortBy = "ProjectTitle",
bool ascending = true,
int page = 1,
int pageSize = 10,
string projectId = "",
string submissiontitle = "",
string firstname = "",
string lastname = "",
string email = "",
string showreport = "")
{
var selectedSubmissions = Session["SelectedSubmissions"] as ICollection<ProjectSubmissionViewModel>;
//... Uses selectedSubmissions to build bookResources and chapters
Session["reportData"] = viewModel.GetContentsReport(bookResources, chapters);
//...
}
At runtime, the code works. With the unit test, SubmissionIndex sees Session["SelectedSubmissions"] as null.
Am I setting up the fake controller's session wrong? How can I work with the Session while testing?
Update: I often call the SubmissionIndex action from a Redirect:
Session["SelectedSubmissions"] = model.Submissions.Where(s => s.Selected).ToList();
return RedirectToAction("SubmissionIndex", "Project", routeValues);
Have you tried mocking it a bit more directly:
var session = new Mock<HttpSessionStateBase>();
var myCollection = new ICollection<ProjectSubmissionViewModel> { object1, object2... etc };
session.Setup(x => x["SelectedSubmissions"]).Returns(myCollection);
Or you could even return based on a generic input
session.Setup(x => x[It.IsAny<string>()]).Returns(myCollection);
Example
private ProjectController controller;
[TestSetup]
public void Setup()
{
var dbMock = new Mock<db>();
//Set up properties etc
var context = new Mock<HttpContextBase>(MockBehavior.Strict);
context.SetupGet(x => x.Session["SelectedSubmissions"]).Returns(object1);
context.SetupGet(x => x.Session["reportStuff"]).Returns(object2);
controller = new ProjectController(dbMock.Object);
}
[TestMethod]
public void TableOfContentReportTest()
{
var result = controller.SubmissionIndex(
"ProjectTitle",
true,
1, 10,"","","","","",
StaticStrings.Report_TableOfContents) as ViewResult;
// Assert
Assert.IsNotNull(result);
var testSession = controller.processReport();
}

Should I write unit test for controller or service layer or both of them?

I'm learning and trying use unit test for my project. But when I try write a demo with unit test I saw that unit test for controller same like for service layer. Below is unit test code I wrote for controller and service layer
Controller test:
private Mock<ICountryService> _countryServiceMock;
CountryController objController;
List<Country> listCountry;
[TestInitialize]
public void Initialize()
{
_countryServiceMock = new Mock<ICountryService>();
objController = new CountryController(_countryServiceMock.Object);
listCountry = new List<Country>() {
new Country() { Id = 1, Name = "US" },
new Country() { Id = 2, Name = "India" },
new Country() { Id = 3, Name = "Russia" }
};
}
[TestMethod]
public void Country_Get_All()
{
//Arrange
_countryServiceMock.Setup(x => x.GetAll()).Returns(listCountry);
//Act
var result = ((objController.Index() as ViewResult).Model) as List<Country>;
//Assert
Assert.AreEqual(result.Count, 3);
Assert.AreEqual("US", result[0].Name);
Assert.AreEqual("India", result[1].Name);
Assert.AreEqual("Russia", result[2].Name);
}
Service test:
private Mock<ICountryRepository> _mockRepository;
private ICountryService _service;
Mock<IUnitOfWork> _mockUnitWork;
List<Country> listCountry;
[TestInitialize]
public void Initialize()
{
_mockRepository = new Mock<ICountryRepository>();
_mockUnitWork = new Mock<IUnitOfWork>();
_service = new CountryService(_mockUnitWork.Object, _mockRepository.Object);
listCountry = new List<Country>() {
new Country() { Id = 1, Name = "US" },
new Country() { Id = 2, Name = "India" },
new Country() { Id = 3, Name = "Russia" }
};
}
[TestMethod]
public void Country_Get_All()
{
//Arrange
_mockRepository.Setup(x => x.GetAll()).Returns(listCountry);
//Act
List<Country> results = _service.GetAll() as List<Country>;
//Assert
Assert.IsNotNull(results);
Assert.AreEqual(3, results.Count);
}
At the controller level, I tend to write end-to-end tests. No mocks, no fakes, only the real things.
The reason is that in the test you have above, your unit test is coupled to the implementation details of your controller action. Suppose you no longer use a repository, or unit of work, your test would no longer even compile. At this level, you should be concerned about testing behavior, not implementation.
I unit test isolated domain models, integration test the rest.

More Elegant way to return json array to ASP.NET MVC

{Sorry new to JSON}
I need to build up an array of resources (Users) and pass it in to my view, might be a better way than what ive done below? (Demo)
My model is simply
public class ScheduleUsers
{
public string Resource{ get; set; }
}
On my controller
var users = new JsonArray(
new JsonObject(
new KeyValuePair<string,JsonValue>("id","1"),
new KeyValuePair<string,JsonValue>("name","User1")),
new JsonObject(
new KeyValuePair<string, JsonValue>("id", "2"),
new KeyValuePair<string, JsonValue>("name", "User2"))
);
model.Resources = users.ToString();
Why don't you just return a list of entities as a JSON result, like:
public class CarsController : Controller
{
public JsonResult GetCars()
{
List<Car> cars = new List<Car>();
// add cars to the cars collection
return this.Json(cars, JsonRequestBehavior.AllowGet);
}
}
It will be converted to JSON automatically.
I did this and this works
JavaScriptSerializer js = new JavaScriptSerializer();
StringBuilder sb = new StringBuilder();
//Serialize
js.Serialize(GetResources(), sb);
public List<ScheduledResource> GetResources()
{
var res = new List<ScheduledResource>()
{
new ScheduledResource()
{
id = "1",
color = "blue",
name = "User 1"
},
new ScheduledResource()
{
id = "2",
color = "black",
name = "User 2"
},
};
return res;
}

Why isn't my database being created in ASP.NET MVC4 with EF CodeFirst

I've been following along with a tutorial by Julie Lerman about using EF CodeFirst to generate the database from code. I'm using MVC4 and working with the default controllers. All I want to do is generate the database. However, in her tutorial, she's working with a console application and calling a create_blog method in her Main function. The create_blog function does the work of creating the database as the name suggests.
In my Global.asax, I have this:
Database.SetInitializer(new CIT.Models.SampleData());
This is my SampleData class:
public class SampleData : CreateDatabaseIfNotExists<Context>
{
protected override void Seed(Context context)
{
base.Seed(context);
new List<Software> {
new Software { Title = "Adobe Creative Suite", Version = "CS6", SerialNumber = "1234634543", Platform = "Mac", Notes = "Macs rock!", PurchaseDate = "2012-12-04", Suite = true, SubscriptionEndDate = null, SeatCount = 4, SoftwareTypes = new List<SoftwareType> { new SoftwareType { Type="Suite" }}, Locations = new List<Location> { new Location { LocationName = "Paradise" }}, Publishers = new List<SoftwarePublisher> { new SoftwarePublisher { Publisher = "Adobe" }}},
new Software { Title = "Apple iLife", Version = "2012", SerialNumber = "123463423453", Platform = "Mac", Notes = "Macs still rock!", PurchaseDate = "2012-11-04", Suite = true, SubscriptionEndDate = null, SeatCount = 4, SoftwareTypes = new List<SoftwareType> { new SoftwareType { Type="Suite" }}, Locations = new List<Location> { new Location { LocationName = "81st Street" }}, Publishers = new List<SoftwarePublisher> { new SoftwarePublisher { Publisher = "Apple" }}},
new Software { Title = "Microsoft Office", Version = "2012", SerialNumber = "12346231434543", Platform = "PC", Notes = "Macs really rock!", PurchaseDate = "2011-12-04", Suite = true, SubscriptionEndDate = null, SeatCount = 4, SoftwareTypes = new List<SoftwareType> { new SoftwareType { Type="Suite" }}, Locations = new List<Location> { new Location { LocationName = "Paradise" }}, Publishers = new List<SoftwarePublisher> { new SoftwarePublisher { Publisher = "Microsoft" }}}
}.ForEach(s => context.Software.Add(s));
}
}
I get no errors when I compile. I just get no database. I looked in my App_Data and all that's there is the default database. I have a dbContext that is getting called because when I had errors in it, they pointed to that file. Do I need to have some kind of create method that is called when the site first compiles?
SetInitializer only sets the initializer strategy and the strategy is executed the first time you access the database. Try adding the following after calling SetInitializer
using (var context = new Context()) { context.Database.Initialize(true); }

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

Resources