Alright.
So I figure it's about time I get into unit testing, since everyone's been banging on about it for long enough. I've installed NUnit and gone through a few "intro to unit testing" type tutorials.
I'm currently putting together a small framework to help with the rebuild of one of our web apps, so I've created a VS2008 project for my framework and I want to unit test it as I go.
How on earth do I go about unit testing the WebControls? The methods are all protected or private, and since it's a framework, there isn't much else but WebControls.
Any pointers?
Burns
You can do model-view-controller or model-view-presenter type architectures without using a full blown framework. You already found out that unit-testing ui-components is difficult. There are ways around that but you probably don't want to go that route. Usually this will make your tests very hard to maintain, more maintenance nightmare's is something programmers can do without :-)
Try to separate out the functionality you want to test in a "controller" or "presenter" class. Then test that class. To make it more testable you can hide the usercontrol class (the view) behind an interface and make the controller or presenter talk to the view through the interface. That way you can mock up the view in your tests.
I know this sounds like a lot of work and it seems like a workaround but if you get used to this it's a realy nice architecture that makes it far easier to change ui behaviour. You can always start using a "real" mvc framework when you realy need it :-)
Ues the assembly:InternalsVisibleTo attribute and you'll be able to access those private members.
Put it in your webcontrol project's AssemblyInfo.cs (under Properties node)
[assembly:InternalsVisibleTo("YourTestProjectName")]
You have found the biggest pain point of ASP.NET. As far as sealed, private classes that hinder unit testing.
This is the main reason that TDD people will use a MVC framework (ASP.NET MVC, Castle MonoRail) as it provides a clear seperation from your view templates and your controller logic. The controllers are fully testable.
You could also look at testing components through the browser as a user would see them using a testing framework such as WebAii. I've seen it work and its pretty cool. I've also been told you can plug it into automated builds but I've not seen that as of yet.
Hope it helps ...
This is an old article by now, but I was using NUnitASP to write nunit tests for asp.net WebControls in 2004. That article gives a detailed example of testing a simple control using their concept of creating a corresponding "Tester" class that encapsulates the details of your control from you tests. The Tester can (should) also be in the same assembly as your control so can share some things between them (e.g. utility functions, constants, etc.).
I used the technique (and others use variants of the technique) still today to test very sophisticated controls.
I hope that is helpful.
The MVC framework mentioned above is the best way to test what the control does. However testing how it works is a bit different.
This is totally off the cuff but you could make the user control expose some protected methods and properties to return validation information and then have a testing user control inherit it. That control could populate fields, press buttons and what not. Kind of messy but it could work.
You can also take a look at this Rhino Igloo framework. It is a compromised MVC framework for WebForms.
Ivonna
can test WebControls in isolation, within the Asp.Net context
Just call session.GetControl("Path.ascx") and verify that it has all necessary properties.
You test them like this:
[Test]
public void ConditionQueryBuilderTest_RendersProperHtml()
{
var sw = new StringWriter();
var queryBuilder = new ConditionQueryBuilderStub
{
ID = "UnitTestbuilder",
QueryBuilderURL = #"\SomeAspxPage\SomeWebMethod",
ResetQueryBuilderURL = #"\SomeAspxPage\OnQueryBuilderReset",
FilterValuesCollection = new Dictionary<int, string> { {15, "Some Condition"}}
};
queryBuilder.RenderAllContents(new HtmlTextWriter(sw));
AppendLog(sw.ToString());
Assert.AreEqual(ExpectedHtml, sw.ToString()); // ExpectedHTML is the raw expected HTML
}
Here is my stub:
internal class ConditionQueryBuilderStub : ConditionQueryBuilder // ConditionQueryBuilder is a WebControl
{
internal void RenderAllContents(HtmlTextWriter writer)
{
RenderContents(writer);
}
}
Related
I am developing a simple project in MVC 6 and bit confused about whether to use DI or not.
I have a view that POSTs to an action - AddData(). Now inside AddData() action I instantiate a couple of classes, say Class1 and Class2, and then invoke their methods to get the job done.
Now my confusion is - In MVC 5 I used to create local instances of Class1 and Class2 inside the action and then call methods on them. This was without any DI.
In MVC 6 do I need to DI Class1 and Class2 in the controller? They are needed only in AddData() action. So is this situation good for DI or traditional local objects would be better?
Please clarify.
Dependency injection is a tool on your developer toolbox that should be used when needed. It will allow you to follow principles like SOLID, which will make your application design better, and it will be of invaluable help if you plan to do unit testing.
IMHO it is a great thing that dependency injection is now fully
integrated across the whole ASP 5 pipeline. This way, whenever you
need it, you won't have to fight the framework as the seam for your
code is already there.
But the fact that you can now use it, doesn't mean you should always use it. Use your judgement!
If you are writing some throwaway code or a very simple app, and you really think dependency injection is overkill, then don't use it. But at least you have taken a conscious decision!
Of course, the easier it is to apply DI, the more you might end up using it even for simple projects or throwaway code.
It is better to do so, so that in case you want to test your app later on, you can substitute with mocks, for instance. However, if you do not care about testing or if the app is really simple, then I don't see a reason against simply instantiating them inside the controller.
Without knowing what "Class1" and "Class2" are used for, this can't really be answered.
If they are models, then no, you wouldn't use DI.
If they are services/utilities, then yes, ideally use DI.
However - there's no difference in the architecture of DI between MVC5 and MVC6, so if you are not using DI in MVC5 then there's no reason to suddenly need to when you move to MVC6 unless you want to improve your practices.
Note there are some 'simple' IoC/DI frameworks that make this very easy and you can always use "poor man's DI" where you have a constructor with the class and one without, eg:
public Controller1()
{
this.class1 = new Class1();
}
public Controller1(Class1 class1)
{
this.class1 = class1;
}
(many people discourage this, but it's an option)
First way, that i always used before, is to define design data in xaml:
d:DataContext="{d:DesignDataSource=/DesignData/MainPivot/ProductCategoriesDesignData.xaml}"
However, after starting using mvvm light, i found out its own way. via ViewModelLocator:
if (ViewModelBase.IsInDesignModeStatic)
{
// Create design time view services and models
}
else
{
// Create run time view services and models
}
So which one is preferable? (not sure if second way is accessible from Blend, for example)
One of the nicest features in MVVM Light is how it handles design-time data.
Here's why I really like using design-time services rather than
d:DataContext="{d:DesignDataSource=/DesignData/MainPivot/ProductCategoriesDesignData.xaml}"
You'll write less design-time code. You'll almost always have more viewmodels than services.
Your viewmodels get used properly with their logic being tested properly. They make calls to the mock services and process the data as they would normally.
The mock services may actually point out bugs in your viewmodels.
All the design-time code gets removed from the Xaml. It's cleaner
What is the best way to test data access layers and business logic in mvc 3 solutions?
I currently have a project where I am using repository classes to access databases, which in turn use hibernate. When I try to create a unit test for them in the auto generated unit tests, they always fail since the configuration for nhibernate is in web.config and and it doesnt try to look there. What am i doing wrong? This particular method returns this error
"The Web request 'http://localhost:35601/' completed
successfully without running the test"
The test methods look like this
[TestMethod()]
[HostType("ASP.NET")]
[AspNetDevelopmentServerHost("C:\\Users\\...", "/")]
[UrlToTest("http://localhost:35601/")]
public void GetByIdTest()
{
string someid= "..";
SomeObj actual = MyRepository.GetById(someid);
Assert.AreEqual(some, SomeObj.id);
}
How do i get this to work properly?
Putting the settings in the app.config should solve the issue you posed above however, the more correct answer is that you should be using a mocking framework to mock the nHibernate session.
The fact that you found an area that you would need to change to accomodate testing is great!!! That is one advantage of unit testing; you find coupling in your code that should be refactored.
I found another post that addresses what you are trying to do directly Mocking an NHibernate ISession with Moq. There are two answers in the post that offer to approaches which may be helpful.
I hope this helps. I havent used nHibernate so I can't speak authoritatively about it or that the link above will provide you with an answer, but each answer has ten upvotes so it looks like it was a solid post!
Having never done an MVC site I am about to start a project for a very large one. I feel confidant enough to do it, but I have one thing I need help figuring out.
We are definitely going to be using an "Entity First" method and have a single .edmx file defining the models, there are multiple reasons for this but just know that this is a definite piece of the puzzle.
So the piece I need to figure out is how to come up with an elegant way to do validations against Entities on a page, without hand coding each page, at least for the majority of things.
Are there any already popular methods for doing some basic validations? Things like MaxLength or Required or MinDate, etc?
Anything more complex than that and I understand I'd have to code it myself, but this site is going to be very large and I really need to find a way to speed some of the basic tasks up.
EDIT
I should point out a couple important facts.
1) Our database already exists and was created by a DBA before developers even came into the picture.
2) There are hundreds of tables and stored procedures already created.
3) When changes will need to be made to the database, they will go through the DBA, who we will not always have instant access too.
First of all, if you use Entity Framework Code First, you don't have a .edxm file storing your models or relationships between them: you just write your POCO (Plain Old CLR Object) classes, and that's it — Code First will figure out the relations between your models based on naming conventions.
To validate your (view) models, I recommend using FluentValidation or DataAnnotations. Both let you define validation rules in one place, either using a fluent validation API in different entity validation classes (FluentValidation) or using attributes to decorate your entity properties (DataAnnotations). The advantage of DataAnnotations over FluentValidation is that you get additional client-side validation out of the box.
Whichever framework you choose, both ship with a bunch of predefined validation rules like Required, Range, or MaxLength (see Fluent Validation for .NET or System.ComponentModel.DataAnnotations Namespace for examples).
I would 100% absolutely still use some POCO class. Download the DBContext generator template that will then create the code first from your model, OR use the Entity Framework Power Tools to reverse engineer an existing database. The down side to these methods though is that you won't get client side validation, only when saving it will you get the validation. You can however still add your validation attributes if you so choose for client side validation in addition using
MetaData Classes to use Data Annotations on your properties and get client side validation using the built in jQuery unobtrusive validation.
However - what we're talking about here goes against the basic design of MVC good practices anyways. Ideally your views should have ViewModels that are at times only a portion of an entity, in this case your validation attributes are still generated on your properties as DataAnnotations in MetaDataClasses.
If you feel this is all too much work and you are fine with just the server validation and have made a decision not to use ViewModels and rely on the Entity Frameworks validation- or use ViewModels and still rely on EF validation, then you will need a handler like the following in your controller (or other layer that has been given access to ModelState) to catch the following exception. Note I use AutoMapper to copy the properties between my ViewModel to my Entity.
Entity Framework Power Tools (right click in your project in solution explorer after its installed and there will be an new 'Entity Framework' menu -> Reverse Engineer - note it doesnt generate [TimeStamp] attributes and forgets to put in schema names - besides that its pretty good)
[HttpPost]
public ActionResult Create(CustomerCreateViewModel customerViewModel)
{
if (ModelState.IsValid)
{
try
{
Mapper.CreateMap();
Customer customer = Mapper.Map(customerViewModel);
var repository = new CustomerRepository(db);
repository.Save(customer);
return RedirectToAction("Edit", new { id=customer.CustomerId});
}
catch (DbEntityValidationException ex)
{
foreach (var error in ex.EntityValidationErrors.First().ValidationErrors)
{
this.ModelState.AddModelError(error.PropertyName, error.ErrorMessage);
}
return View();
}
}
return View(customerViewModel);
}
Jon Galloway has a nice article called Generating EF Code First model classes from an existing database which I think will help you greatly in getting your application up and going from what you described.
Secondly, from having built out our own MVC application so far, I've found that you're really not going to be working directly with Entity Framework models directly very often. Most of the time you'll end up with some type of view model for doing your gets and posts to. Adding DataAnnotations to those class properties will make it very easy for you to do your validations on the client side. Once you have validated the data from the client side and checked your entities against any business rules, you really should then be able to trust the data and use EF to do your basic CRUD work with.
Good luck, and hope this helps you some with your project.
What Marius is trying to tell you is that "Code First" refers to your "model" being defined by fluent code mappings that do not rely on an .edmx file. Therefore, if you're using an .edmx file, you're not doing "code first". You're doing either "Database First" or "Model First" (both of which use the .edmx).
In your case, you already have a database, so you're using the "Database First" approach, using EF 4.1 DbContext. This is not "Code First" (or as you incorrectly stated, Entity First). This is not a semantic quibble, as "code first" has a very specific meaning. This is not it.
Now, on to the rest of your question. Since all your database access has to go through stored procedures, Entity Framework is not a good choice in my opinion. You would be better off using something like nhibernate, which has much better stored procedure support.
EF is intended to represent your relational data model in objects, and generates all its own sql to access and fill these objects. If you have to go through the sprocs, EF will be a constant uphill battle for you.
Im trying to generate views in unit tests but i can't get around the missing VirtualPathProvider. Most viewengines use the VirtualPathProviderViewEngine base class that gets the provider from the current HostingEnvironment.
protected VirtualPathProvider VirtualPathProvider {
get {
if (_vpp == null) {
_vpp = HostingEnvironment.VirtualPathProvider;
}
return _vpp;
}
set {
_vpp = value;
}
}
In unit tests there is no HostingEnvironment, even if i create one there is no current VirtualPathProvider.
How can i workaround this problem? Do i have to create a custom FakeWebFormViewEngine?
There are features coming in VS Team System 2010 for the Acceptance Testing which would be appropriate for what you are trying to do. As mentioned by Gregory A Beamer Unit tests for MVC are done to the controller. You can also test the Model depending on how you implement your model.
This is where there is a lot of controversy. Some people look at the model as business entities where I look at them as representations of the model specific to the View. More of a View Model. Since there is no real functionality in my model I do not have to test it. I test my DAL, Business Logic Layer outside of the MVC. MVC really is all part of the presentation layer. It is layering of your Presentation not your application. You still layer your application.
As far as Unit testing goes the controller is where you test. You can test your model if there are methods that require testing. As for the views they are acceptance tested by users or through automation like Watin.
I tried to do this as well. Unfortunately, it is not just the VirtualPathProvider (VPP) that is the problem. The VPP is used to map the view or partial view to a physical path to determine the existance of the file. Unfortunately, the ViewContext ends up with the virtualpath, not the physical path, so when the view is rendered the Builder uses properties of the HostingEvnironment which does not exist.
If you are using a version of Visual Studio with Testing, then you could use a Web Unit Test. This will allow you to use the browser to call the URL and then parse the response to check for values.
Pardon me if this sounds ignorant, but what is the purpose of generating views? I may be missing something, but the primary focus of unit tests is "testing the unit". In a properly set up ASP.NET MVC application, the code that needs to be tested is in the controller and below. In fact, I would say, if properly developed, it is below.
The test of the view is a user acceptance test. I see nothing wrong with automating this, by any means, but I am not sure this is something that has to be done with a unit test.
Am I missing something?
You can try Ivonna for integration (and, to some extent, unit) testing your Views.