DataContext crashes when unit testing - asp.net-mvc

I am using Linq to SQL in my project. I have a part of the code that calls
DataContext db = new DataContext()
This works as expected when running the website however when calling this from within my unit test I get an error object not set to an instance...
Do you know why this is?
I know I should Mock the data context for testing but there is only two tests that use this that I need completed for this stage of the project. Then I will go in and Mock.
I just don't see why it doesn't work.
Edit:
In my controller I have the line
CandidateRegistrationViewModel viewModel = new CandidateRegistrationViewModel("PersonalDetails", candidate);
The Model has a member db:
public class CandidateRegistrationViewModel
{
private EmployDirectDataContext db = new EmployDirectDataContext();
This class then uses db to populate select boxes.
It all works when I run but in the unit test I get an error upon creating the datacontext.
[TestMethod]
public void PersonalDetailsStepPostShouldRedisplayIfDOBSuppliedInWrongFormat()
{
// Arange
var controller = CreateCandidateController("Dean");
repository.Add(FakeCandidateData.CreateCandidate(controller.member.UserId()));
FormCollection formCollection = FakeCandidateData.CreatePersonalDetailsStepFormCollection();
formCollection["DOB"] = "24/2009/87"; //DOB in wrong format - should be dd/mm/yyyy
controller.ValueProvider = formCollection.ToValueProvider();
// Act
ViewResult result = (ViewResult)controller.PersonalDetailsStep(formCollection);
// Assert
Assert.AreEqual("", result.ViewName); //ViewName is returned as empty if same as Action name
}
Both of the projects have the same connection string in the app/web.config
<add name="EmployDirectDBConnectionString" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\EmployedDirectDB.MDF;Integrated Security=True;User Instance=True"
providerName="System.Data.SqlClient" />

Testing the Data Context falls more into the purview of an Integration Test. The mocks are more appropriate for your repository interface. Your repository will hold a valid reference to the DataContext object during your integration testing.

Your unit test assembly probably does not have the right connectionstring compiled into the settings. That's why I always use:
var db = new MyDataContext(SomeConfigClassIMade.ConnString) {...}
so I can more tightly control how the connection string works,.

I an not sure why you would want to test the DataContext itself... (I may be wrong and I am sure someone will tell me if I am) but would you just test the DataAccess or Repository class that uses the DataContext...
Other than that it probably just doesn't have the correct connection string...

Related

Cannot connect to my edmx with my data context

I've not used VS MVC for a while but I'm writing a project which requires connecting to a Sql database which I've installed as an edmx file SwitchDB.edmx in my DAL folder. In the past I've set up my data context file which I then use to reference the data in my controller, the model help me to order the data in the correct way.
This is how my data context file looks
namespace Switches.DAL
{
public class SwitchContext : DbContext
{
public SwitchContext()
: base("DefaultConnection")
{ }
public DbSet<Switch_List> SwitchList { get; set; }
}
}
I've set up the "DefaultConnection" in my Web.config under connectionStrings and my model Switch_List.cs has the file settings. When I declare the DB context in my controller as below
private SwitchContext db = new SwitchContext();
Then I would expect to reference the SwitchContext to get my data, like this
var switches= db.SwitchList .ToList();
However, when I run the project and reference db in debug I get the following error message 'the function evaluation requires all threads to run'. The DB context SwitchContext is clearly not getting access to the Switch.edmx so what am I forgetting?
I had a similar problem, but you should see the connection properties using an IDE button (to re-evaluate the expression).
However, when you get to the part of db.SwitchList.ToList() does it generate any exceptions?

Issue unit testing an asp.net MVC controller that inherits from a custom base controller

So i'm using Moq and starting to write unit tests for my controller actions.
All of my controllers inherit from a base CustomController class that provides a userId property set in the constructor to be the value of Membership.GetUser().ProviderUserKey. This way I can pass the userId to my service layer simply by passing contactId.
This does not seem to work well with this unit test:
var serviceMock = new Mock<IFormService>();
serviceMock.Setup(g => g.GetForm(2)).Returns(new FormViewModel() {ID = 2, Name = "Mock Form"});
var controller = new FormController(serviceMock.Object);
var result = controller.Index(2);
Assert.IsNotNull(result, "View Result is null");
It throws an exception on the base CustomController where it tries to set the userId from Membership.GetUser().ProviderUserKey.
"UnauthorizedAccessException: Access to the path 'C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow\App_Data' is denied."
Has anyone else come across this issue or have any thoughts on a way around it?
You maybe forget to set the membership provider in your webconfig:
<system.web>
<membership defaultProvider="SqlProvider" userIsOnlineTimeWindow="20">
</system.web>

Unit test wiring of MVC, FluentValidation, and Ninject

I have set up an MVC web project with FluentValidation and Ninject using the Ninject.Extensions.Mvc.FluentValidation package. I followed the documentation of that package directly.
I'd like to write an automated test that verifies this wiring, and checks that the model validation will use the FluentValidation validators as expected. I'm having a hard time spinning up the right pieces of the MVC application in my test in order to do this.
Basically, I want to spin up the MVC app enough so that the Ninject kernel is created, the model binders are wired, and validators are created. Then I want to try to validate an entity through the MVC model validation and make sure that expected messages from the validator are showing up.
What is the best way to automating the testing of the interaction between Ninject, MVC, and FluentValidation?
I have similar setup but I use Unity instead of Ninject.
My IoC container inherits UnityContainer where I register all my repos, validarots, etc. I benefit from this because I have validators with repo dependencies (e.g. UserRegistrationValidator checks for unique user names).
My IoC container also implements IValidatorFactory. I use it register a global ModelValidatorProvider like this:
var ioc = new IoCContainer();
ModelValidatorProviders.Providers.Add(new FluentValidationModelValidatorProvider(ioc));
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
With this setup I know that my validators will intercept model validation in controller actions but only if validators are resolved by ValidatorFactory.
So basically I have 2 groups of tests
- IoC tests
With these I test if my IoC container can resolve a validator for a model. With Unity it looks something like this:
// Arrange
var ioc = new IoCContainer();
// Assert
Assert.IsTrue(ioc.IsRegistered(IValidator<MyModel>));
If you have all your models under one namespace you could even write a single unit test by getting all types from specific namespace and check if IValidator is registered for them in a loop.
- Validator tests
These are common tests to test my (view)models:
// Arrange
var validator = new MyModelValidator();
var model = new MyModel{ Name = null };
// Assert
validator.ShouldHaveValidationErrorFor(x => x.Name, model)
With this there is no need to spin application, you just test what you create.
Hope this helps.
What we use here for the integration test is Selenium Webdriver, you can get it with NuGet. We write code usign page pattern so it's easyer to maintain.
When I want to check if a requiered field or any other custom validation I do the following :
[TestFixture]
public class CenterTests : TestBase
{
[Test]
public void CreateViewAndEditShouldWork()
{
S.OpenWithCI();
var loginPage = new LoginPage(S);
var homePage = loginPage.LoginValidUser("email", "Password");
var centerListPage = homePage.ClickCenterAndRoomLink();
var centerPage = centerListPage.ClickCreateLink();
//Create
centerPage.CreateInvalidCenter();
Assert.That(S.FindElement(By.CssSelector("span[for=Name]")).Text, Is.StringContaining(Strings.Error_Required));
Assert.That(S.FindElement(By.CssSelector("span[for=EnglishName]")).Text, Is.StringContaining(Strings.Error_Required));
centerListPage = centerPage.CreateValidCenter("Saguenay", "Sag", "2089 blv Talbot");
Thread.Sleep(2000);
S.ExpectSuccessNotice(Strings.CenterCreatedSuccessfully);
}
}
And here's the code of my TestBase helper class :
namespace Afi.AutomatedTests.Helpers
{
[TestFixture]
public class TestBase
{
protected IWebDriver S;
[SetUp]
public virtual void TestSetup()
{
S = new ChromeDriver();
S.Manage().Window.Size = new Size(1024, 768);
S.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10));
}
[TearDown]
public void TearDown()
{
S.Quit();
}
public string GetUrl(string relativePath)
{
if(!relativePath.StartsWith("/"))
throw new ArgumentException("Relative URL must begins with /");
return "http://afi.local" + relativePath;
}
}
}
All those tests are in an other project call AutomatedTests and I can run them the same way I run unit test (resharper/nunit). It uses Chromedriver to do the tests.
Let me know if you need more informations.

How to Unit/Integrate Test Views to detect breaking changes

I have just started learning asp.net mvc and one reason of the primary reasons has been to move to TDD.
I am writing a small dashboard application which has reports. In this app, I had a primary controller called ReportsController, which right now has just one method, GetReport that takes in a query and returns a view if the query meets certain conditions, else returns an error message.
[HttpGet]
public ActionResult GetReport(string query)
{
//calls the QueueRep and gets back DataTable
ReportQuery reportQuery = new ReportQuery(query);
if (reportQuery.IsValidQuery)
{
queryRepository.ExecuteReportQuery(ref reportQuery);
}
else
{
return View("Error");
}
ViewData.Add("ResultDataTable",reportQuery.ResultDataTable);
return View();
}
I had written 2 unit tests for this as follows
public void GetReport_Should_Return_Error_View_For_Malicious_Query()
{
//Arrange
string query = "drop table userInfo";
var controller = CreateReportsController(query);
//Act
var result = controller.GetReport(query) as ViewResult;
//Assert
Assert.AreEqual(result.ViewName, "Error");
}
[Test]
public void GetReport_Should_Return_View_With_DataTable_For_Correct_Query()
{
//Arrange
StringBuilder sb = new StringBuilder();
sb.Append("SELECT Year(CreatedOn) as Year, Month(CreatedOn) as Month, Count(CREATEDON) as NewEmployers");
sb.Append("FROM dbo.UserInfo WHERE DefaultPurpose = 1 GROUP BY Year(CreatedOn), Month(CreatedOn)");
string query = sb.ToString();
var controller = CreateReportsController(query);
//Act
var result = controller.GetReport(query) as ViewResult;
//Assert
Assert.IsTrue(result.ViewData.ContainsKey("ResultDataTable"));
Assert.IsTrue(result.ViewData["ResultDataTable"].GetType() == typeof(System.Data.DataTable));
}
Now, due to conflict with SSRS, the server/Reports was pointing to SSRS instead of Reports controller so I changed name of ReportsController to MyReportsController. I used refactor for the name change and changed my unit tests in the test project as well and ran the unit tests. Everything is fine.
But now when I ran actual app, I got an error. Basically, the folder name of the views had to be changed from Reports to MyReports. How can I test these kind of scenarios. Is only using functional testing tools like selenium? Or I could have written my tests differently?
I don't think there is anything you should/could do to test this with unit tests, but integration tests with Selenium is a good way to go about it:
http://seleniumtoolkit.codeplex.com/
Yes, manual testing or functional test tools like Selenium are the only way to find these breaking changes.
The reason is because with unit testing you are only testing small bite sized parts of your code. So testing a controller's action method is great! In that test you need to remember that your testing your own code and not the asp.net and/or mvc frameworks. Now, to -render- a view result, this is handled outside of your action method. Secondly, we assume that the rendering logic (how to render) has been tested by Microsoft so we don't want waste time testing that either.
So this means we need to join independent modules together in a single test. When we have 2+ modules or areas etc to test, we suddenly jump out of unit testing and into manual or functional testing.

Mocking FormsIdentity.Ticket.UserData with Moq

As part of a unit test I am trying to mock the return value of FormsIdentity.Ticket.UserData
The following will NOT work but it should give an idea of what I am trying to do:
var principal = Mock<IPrincipal>();
var formsIdentity = Mock<FormsIdentity>();
formsIdentity.Setup(a => a.Ticket.UserData).Returns("aaa | bbb | ccc");
principal.Setup(b => b.Identity).Returns(formsIdentity.Object);
The code I am trying to test looks something like this:
FormsIdentity fIdentity = HttpContext.Current.User.Identity as FormsIdentity;
string userData = fIdentity.Ticket.UserData;
All I want to do in my unit test is fake the return value from FormsIdentity.Ticket.UserData. But when I run the code in the first section I get an error when trying to mock the FormsIdentity. The error says the type to mock must be an interface, abstract class or non-sealed class.
I tried to use IIdentity instead of FormsIdentity (FormsIdentity is an implementation of IIdentity) but IIdentity doesn't have .Ticket.UserData.
So how can I write this test so that I get a value from FormsIdentity.Ticket.UserData?
I'm not a Unit Test expert, by any means, just getting my feet wet in the area.
Isn't it overkill to mock out the Identity in a unit test, because the Identity code is code that you can assume works already in isolation? (ie. it's Microsoft's code?) For example, when unit testing your own code, you wouldn't need to mock out one of the Framework objects. I mean, would you ever need to mock a List or a Dictionary?
That being said, if you REALLY want to test your code in isolation or for some reason have super fine control over the data returned in Userdata, can't you just write an Interface for the interaction between the Identity and your code?
Public Interface IIdentityUserData
Readonly Property UserData As String
End Interface
Public Class RealIdentityWrapper
Implements IIdentityUserData
Private _identity as FormsIdentity
Public Sub New(identity as FormsIdentity)
'the real version takes in the actual forms identity object
_identity = identity
End Sub
Readonly Property UserData As String Implements IIDentityUserData.UserData
If not _identity is nothing then
Return _identity.Ticket.UserData
End If
End Property
End Class
'FAKE CLASS...use this instead of Mock
Public Class FakeIdentityWrapper
Implements IIdentityUserData
Readonly Property UserData As String Implements IIDentityUserData.UserData
If not _identity is nothing then
Return "whatever string you want"
End If
End Property
End Class
'here's the code that you're trying to test...modified slightly
Dim fIdentity As FormsIdentity= HttpContext.Current.User.Identity
Dim identityUserData As IIdentityUserData
identityUserData =
'TODO: Either the Real or Fake implementation. If testing, inject the Fake implementation. If in production, inject the Real implementation
Dim userData as String
userData = identityUserData.UserData
Hope this helps

Resources