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.
Related
I want to unit test my cshtml files to ensure they compile successfully as recently I've had some issues where at run time there were failures due to the views expecting properties that weren't present. I am trying to use RazorEngine to check this, and here is my attempt at a unit test:
public void LayoutCshtml_AnyCase_ViewCompilesSuccessfully()
{
var model = new Model();
var templateName = File.ReadAllText("PathToView/_Layout.cshtml");
var result = Engine.Razor.RunCompile(templateName, "key", typeof(Model), model);
//Assertion will go here
}
I will add the assertion later but at the moment just want the view to compile. The templateName correctly picks up the right .cshtml but the result fails because of error:
The predefined type
'System.Runtime.CompilerServices.ExtensionAttribute' is defined in
multiple assemblies in the global alias;
Is anyone familiar with using RazorEngine to test please?
I write unit test which method using database to check exist record,but when i debug on application it return true,but when debug on unit test it return false,i think i missing some thing like mock from database to create data.i newbie of unit test.pls help me solve it.
public void Test_Exist_Record_Db(TriangleModel triangle, bool regext)
{
//Arrange
bool isExist = false;
//Act
isExist = _repository.IsCalculatedBefore(triangle);
//Assert
Assert.AreEqual(isExist, regext);
}
This method using database
public bool IsCalculatedBefore(TriangleModel triangle)
{
using (var db = new TriangleModelDataContext())
{
var temp =
db.TriangleModels.FirstOrDefault(
x =>
x.LengthSideA ==triangle.LengthSideA &&
x.LengthSideB == triangle.LengthSideB &&
x.LengthSideC == triangle.LengthSideC);
if (temp != null)
{
return true;
}
return false;
}
}
A test called against a real resource, like a database, is called an integration test and not an unit test. In your case you don't need to do an integration test, because you're using the entity framework which is extensively tested by the EF developers.
To solve your problem: I believe, that your connection string in development environment is not the same, than the one in your test environment. The DbContext has a property like Connection (I don't know the exact name, but with IntelliSense or inspecting the object during debugging the test you should be able to find it) with which you can compare the connection strings. But I would rather mock the DbContext. You can read about mocks on Wikipedia.
And, if you didn't knew it, instead of using .FirstOrDefault() and then checking for null, you can use the .Any() method, that returns a boolean, which tells you, if there is a given entry fulfilling the condition.
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.
I'm new to MSpec and would like to know if the way I wrote my test for ASP.NET MVC is correct. The test passes but I don't really like the way it's written and it seems awkward. I'm certainly missing something.
public class AccountControllerTests3
{
protected static AccountController controller;
static IFormsAuthenticationService formsService;
static IMembershipService membershipService;
protected static ActionResult result;
protected static LogOnModel model;
Establish context = () =>
{
var controllerBuilder = new TestControllerBuilder();
formsService = MockRepository.GenerateStub<IFormsAuthenticationService>();
membershipService = MockRepository.GenerateStub<IMembershipService>();
model = MockRepository.GenerateStub<LogOnModel>();
controller =
controllerBuilder.CreateController<AccountController>(new object[]
{
formsService,
membershipService
});
};
Because user_logs = () =>
{
bool rememberMe = false;
membershipService.Stub(
x => x.ValidateUser("bdd", "mspec")).Return(true);
formsService.Stub(x => x.SignIn("bdd", rememberMe));
controller.ModelState.IsValid.ShouldBeTrue();
};
}
[Subject(typeof(AccountController), "LogInTests")]
public class When_logging_into_application_with_good_login_and_password : AccountControllerTests3
{
private It user_should_be_redirected_to_the_home_page = () =>
{
model.UserName = "bdd";
model.Password = "mspec";
result = controller.LogOn(model, string.Empty);
result.AssertActionRedirect().ToAction<HomeController>(
x => x.Index());
};
}
[Subject(typeof(AccountController), "LogInTests")]
public class When_logging_into_application_with_bad_login_and_password : AccountControllerTests3
{
It The_error_message_should_be_shown = () =>
{
model.UserName = "BAD";
model.Password = "BAD";
result = controller.LogOn(model, string.Empty);
controller.ModelState[""].Errors[0].ErrorMessage.ShouldEqual(
"The user name or password provided is incorrect.");
};
}
Thanks in advance,
Thomas
One of my goals when I write tests with MSpec is to get the "Assert" or the "It" down to one line. MSpec is not like NUnit in that it only executes the Context (made up of the Establish clauses from the current class and all base classes and the Because clause) once followed by all of the Specifications (It clauses).
This is designed explicitly to force you to not perform any behavior in the It clauses, but rather observe it.
What you're actually doing here is using MSpec like NUnit. Try and rewrite the tests in a single class (using no inheritance). Work backwards... in the It, place a single line that asserts what you want to assert. Perhaps the AssertRedirect. In the Because, try and put a single line that causes the observations to be observable. This would probably be your call to the controller's logon method. Finally, in the "Establish context" you'd want to put everything else.
After a while, you may want to pull some of the things in the Establish context only into a base class, but in doing so, be sure that your entire subclass stands alone in terms of understanding. A reader shouldn't need to read the base class in order to understand what the actual spec is doing. It's ok to hide ceremonial implementation details, but be sure to hide them behind descriptive method names.
There's another line I'm not sure about:
controller.ModelState.IsValid.ShouldBeTrue();
If this is a test, it should probably be in its own It clause. Though really, do you want to test this? What are you testing here? Shouldn't your controller take an action based on whether or not the model is valid? Shouldn't the result of that action be observable (validation error instead of login error). I just wonder if you really need to test this.
A few other things to check out, first for styling with R#, it seems your tests are falling victim to R#'s defaults. I posted about how to fight this here:
http://codebetter.com/blogs/aaron.jensen/archive/2008/10/19/getting-resharper-and-vs-to-play-nice-with-mspec.aspx
Also, James Broome has some nice MVC MSpec extensions that are worth checking out:
http://jamesbroo.me/introducing-machinespecificationsmvc/
Good luck and Enjoy! Feel free to ping me on twitter if you have any other unrelated questions.
Here's a remark: instead of using CreateController method use InitializeController, because it is compile-time safer and refactor friendlier.
Instead of:
controller = controllerBuilder.CreateController<AccountController>(
new object[] { formsService, membershipService });
Do:
controller = new AccountController(formsService, membershipService);
controllerBuilder.InitializeController(controller);
The first will still compile if you change the controller constructor arguments and it will blow at runtime, while the second will generate a compile-time error.
i have a method that does takes in a object and saves it to the database. But, before i save the object, i do the following...
(psuedo code)
if (IsAuthenticated)
{
foo.UserId = AuthenticatedUser.Id;
}
else
{
foo.AnonEmail = "Jon#World-Domination";
foo.AnonName = "Jon Skeet";
}
try
{
_fooService.Save(foo);
}
catch
{
// Some view, with error stuff now added to
return View(...); ViewData.ModelState.
}
// all good, redirect to the proper next view.
return RedirectToAction(...);
That code works fine, but i'm not sure how to write the two unit tests for a success.
a) User is authenticated with valid data
b) User is not authentiated with valid data.
The reason why i'm not sure what to do is, is that both scenario return the same RedirectToAction(..) view object. So i can successfully test that .. but it doesn't tell me if the object saved contains the authenticated user id or the anon info. It's like i want the first unit test to say
moq up an authenticated user
call method
test if result is RedirectToActionView
test if the foo object that was persisted contains the moq'd user id.
thoughts?
Update
The common suggestion is that i mock the fooService. I'm currently using Dependency Injection and Moq, so could somone show me how i would use Moq? I'm not sure how the DI is important here, though ???
I would mock up the _fooService object, and test what it receives as part of your test. That way your surrounding code remains the same and is untouched, and by checking what _fooService receives, you can assert whether the behaviour is as expected. The return object is not of interest in this case.
How do you mock your _fooService ? You can either implement your own 'test' version (adhering to the same interface as the real world version), or using a mocking framework. Whichever approach you use, your code above needs to be configured with a given implementation of the _fooService (usually on construction - see dependency injection for more info on how this may work)
You might mock _fooService.Save(foo) and inspect the supplied foo.
Maybe you are finding it difficult to test the object because you have more than one activity taking place in a single method.
The overall theme here is controller logic.
Decorate the domain object with user information
Persist the update logic
Determine the next view to render based on success/failure
If you extract another object (IUserDecoratorService) then your code looks like
userService.UpdateUserInformation(foo);
try
{
_fooService.Save(foo);
}
catch
{
// Some view, with error stuff now added to
return View(...); ViewData.ModelState.
}
// all good, redirect to the proper next view.
return RedirectToAction(...);
This method is simple to test as it is 2 simple interactions with the 2 services and a routing decision which you can already test.
Now you just need to write the tests for your new service:
[Test]
public void ShouldDecorateWithUserIdForAuthenticatedUser()
{
{setup authenticated user}
:
service.UpdateUserInformation(foo);
Assert.AreEqual(expectedId, foo.UserId);
Assert.IsNull(foo.AnonEmail);
Assert.IsNull(foo.AnonEName);
}
[Test]
public void ShouldSpoofTheAllKnowingSkeetIfAnonymousUser()
{
{setup anonymous user}
:
service.UpdateUserInformation(foo);
Assert.AreEqual(UnassignedId, foo.UserId);
Assert.AreEqual("Jon#World-Domination", foo.AnonEmail);
Assert.AreEqual("Jon Skeet", foo.AnonName);
}
you still have a reference to your object. At the end of your unit test, couldn't you just assert what the value was foo.AnonEmail or UserId?
Unit tests should not touch an external source, (that's an integration test) so if you go that route you should mock your datasource and then test through your mock.
Do you have access to foo in the test? I'm assuming it's a field on the class. Is there a public getter? If not you may have to use Reflection (I assume that's available in asp.net, but I'm not too familiar with it)
You want to use the DI to get the correct implementation of fooservice into your object, so at testing time you can do this;
(Using Moq)
[TestMethod]
public void Jon_Skeet_Is_Saved_If_User_Not_Authenticated()
{
bool jonWasSaved = false;
var mockFooService = new Mock<IFooService>();
mockFooService
.Expect(x => x.Save(It.Is<Foo>(foo => foo.AnonName == "Jon Skeet")))
.Callback(() => jonWasSaved = true;);
FooManager instance = new FooManager(mockFooService.Object);
Foo testFoo = new Foo();
testFoo.UserId = 1; // this is not the authenticated id
instance.baa(foo);
Assert.IsTrue(jonWasSaved);
}
You may also want to pass in a mock version of whatever service you use to check the AuthetnicatedUser.Id
HTH