I'm doing BDD on an MVC3 project with SpecFlow. My current specification scenario says that:
Given a user is working on the system
When an error is raised
Then the user should be redirected to error page
And display a link to go back where he came from
How can I test a spec like this? I usually test the controller directly, however the Error view given by the standard MVC3 template has no controller, and no controller is used, because is redirected by the HandleError global filter.
In exceptional cases I use Watin to test that the behavior conforms to what the specification says, however to do that I need a view that raises an error, something that when everything is working i do not have.
Any ideas on testing scenarios like this?
I have a few thoughts on this scenario:
1.) "Given a user is working on the system" is a pretty vague step. What code would be found in the step definition? Unless you have a user class that has a WorkingOnSystem method, it might be worth taking this line out.
2.) Without having seen the rest of your code, I think the target of this feature should be the HandleError filter itself. By its very definition, you know that when it is invoked an error has occurred. All you need to do is instantiate the filter, call the appropriate method, and test the results.
Think about it this way: What does "When an error is raised" mean in your system? If your HandleError filter is not the place, then you probably don't have a place. In which case, you'll need to be more specific.
I think the awkwardness around this spec is due to ASP.Net MVC. When you're dealing with a framework of abstractions, you're sometimes left to "wrap" your specs around some part of it. We just can't go end-to-end easily when the parts of the application come from so many places.
Related
I have been searching the web for the issue I'm facing for quite some time now. I found people facing it, but couldn't get an appropriate solution to the problem. The issue is what would be the best way to handle any exception occurred in an template.gsp ? I know I can use a try-catch there so that my controller don't get the exception, but I did find people saying its not a good practice, but failed to answer why. So is it a wrong way and if it is then is there any better solution to deal with this problem ?
The correct way is with a 500 error handler: http://grails.org/doc/latest/guide/theWebLayer.html#mappingToResponseCodes
If you have a lot of logic in your views that could produce a error consider refactoring the code into a tag library which can incorporate better error handling
It depends on what behavior you want for your application with the error.
If a generic error page works for the application - then setup an error page in URL mappings and ignore the error in the controller.
Do you need a nice custom error that is specific for that case - (or possibly display an alternate page? ), if so then you'd need to a try catch (or do some fun with URL mapping and creating an error controller). The objections that come up in Exception handling in Grails controllers arise around the amount of code required for the error handling in the controller vs the rest of the application - with the error handling code being ~40% of each controller method. This causes the code to seem bad/bloated (and apparently violate the CodeNarc "CatchException" rule).
I have come up with a small issue in my application.
I changed the namespace of my main application to be from MyApp.Models to MyApp.ViewModels so that the namespaces were less confusing overall (since that namespace only has view models and no business models). I changed all the references I could find, including in my views, and I re-ran all my unit tests and went through the application, and all seemed fine.
A few days later I got a report that the registration page had an error when it was brought up. After looking it turns out I forgot to fix the namespace on the registration page, and thus it was failing to compile the view.
This worries me. The whole point of unit testing, and one of the biggest lures of Asp.Net MVC, is to be able to have confidence in your application by having everything tested individually automatically so that you know immediately when your modification breaks parts of the system. Views right now seem like a major hole in this.
To be clear, I am aware you are able to turn on pre-compiling a views. However, I do not like this option as it's not a good idea to have this on all the time (as it makes compiling a new build very, very slow), and having a separate configuration scheme for this means it's up to the user to remember to attempt to compile with that configuration scheme to check for view compile errors.
This also completely bypasses checking for runtime errors that may occur. For example, lets say you change the viewmodel that a strongly-typed view is expecting. You would then update the unit test to make sure that the Controller.Action() is returning a view result with the correct view model type, but that does nothing to make sure that the actual view was updated correctly for the new view, and yet this scenario will cause a run-time exception. This is an easy scenario to occur, especially since if the differences in the two view models are only seen in partials used within the view.
Other examples of code that can cause runtime exceptions in views are incorrect loops (possibly caused by changes in a view model), code that checks a user's role (so buttons are only shown for users with credentials), incorrect casts (e.g. for converting a collection into a select list), incorrect code to sort a collection (how a collection is sorted in the display can construed as a view concern, not a controller or view model concern), if strings used for locations of files don't work correctly (T4MVC doesn't integrate well with some things, such as Telerik's script registration system) etc...
The way I see it, there are many things that can cause an exception to occur in the process of rendering a view, and I can't seem to find any way to create unit or integration tests to determine when these occur. I would feel more comfortable if I did not have to check every page to make sure I missed a compile time or runtime error for something that a standard unit test should be able to catch.
What options do I have to do this?
I would prefer to stay away from WaTiN and other GUI testing tools, as for this I am not interested in the actual display of the page, I only want to know if the view renders or if an exception occurs and do not need the overhead of Watin running an IE instance for each test (I also think this will cause issues if I go with continuous integration at a later point).
If you don't want to use WaTIN and IE, how about firing up your web site in IIS Express, and then using HttpWebRequest over each of your Views' urls to check the result is 200 OK. This is a complete integration test.
Otherwise, you have to get the ViewResult from your controller, and call the ExecuteResult method passing in a ControllerContext containing a stubbed HttpContextBase. This gives more of a true unit test, and would be faster, but you've got a lot of mocking and stubbing to do before it will work.
mspec mvc extensions
I am writing some BDD style Spec Flow test which is working out smoothly! Now, I am in a position to test that the data annotations validations are fired. I am thinking that this test should be performed by using WatiN tool since the UpdateModel is fired when the values from the form are posted.
How do you test that the validations are firing?
There are a number of ways you can do this. You dont have to use WatiN to check validations, I am using SpecFlow to call controller methods and then interrogate the ModelState property checking for the errors I expected to be raised from the invalid data I entered.
You can also use WatiN to check that particular error text is displayed on screen by attatching to the browser and using the Find.ByText("Error Message") method.
If you haven't already I strongly suggest having a read of this article, helped me alot when starting out with SpecFlow/WatiN and BDD:
http://msdn.microsoft.com/en-us/magazine/gg490346.aspx
Hope that helps.
By testing them with invalid data...(and valid data)
If your model has an annotate just fire values at it you may write a scenario like
Scenario: Adding an invalid user
GIVEN I am in the add user page
AND I have not filled in the name
WHEN I Add
THEN I should see the error defined in my annotation
more on testing annotations is here http://bradwilson.typepad.com/blog/2009/04/dataannotations-and-aspnet-mvc.html
but you just want them to fire. Remember you are testing from the outside in this case.
Most of the stackoverflow posts about ASP.NET MVC unit testing talk about a specific issue or specific thing to test such as testing HtmlHelpers. Others on the subject of best practices have surprisingly few answers. Available videos I have watched are completely useless in my opinion - and mind blowingly long (by the time you've watched 1.5 hours and not learned anything).
What I want to know from people who've actually been doing this is :
What are the most important things to test first
What doesn't need testing (shock horror for me saying that but I'm not after 100%)
What is hard to test and how have you overcome difficult thins to test.
What things can break in refactoring that a test won't catch.
I'm not new to how to unit test - but I'm very new to actually doing it consistently. I'd really appreciate lessons learned from those who are experts in unit testing ASP.NET MVC.
I'm really looking for specific things you might only find out after having tried it - not jsut general advice like 'use interfaces' - although of course any suggestions are welcome.
Oh and lets say I've decided to use Microsoft's unit testing - just becasue its already there. I think all answers would apply to all testing frameworks though.
Test your routing. You should use RouteLink to remove ambiguity when you generate a URL in your View, but when you submit a URL, you are dependent upon the routing system to select the correct route. So test that the URL patterns you support do in fact return the correct route.
Test your controller actions. Use a mock repository, and test that manually invoking each action has the results you expect.
Test all business logic in your model. This is obvious, and little different from non-MVC applications.
Test any custom view helpers you write. Although I don't generally unit test views, view helpers are different.
Test your JavaScript. There are unit testing frameworks for this, that testing JavaScript is so easy that such frameworks are hardly necessary. But testing JavaScript is incredibly important, due to the tendency of the language to hide errors from you.
If you have written any custom model binders, they need special attention. For one thing, it is a lot easier to debug a model binder via a unit test than when it is "live" in the application.
I'd like to elaborate on testing controller actions:
Verify you get the proper ActionResult. A redirect is different from a view.
Also verify the expected view name. If you rely on the default view, it should be empty.
Verify you get the proper view model.
Verify all branches in your action. Keep them to a minimum and move them to a helper / service when they grow too many.
In short, verify anything from the ActionResult that you will use.
I dont think the answer has to be specific to ASP.NET MVC.
Like any other application, the most important thing you have to test is your core logic.
That is, your model code and your controller actions.
I am using AjaxSubmit to post a form and there are server side validations done using XVal (RuleException way). I am not using the try/catch way to add error to Model and then send to view. Instead - I want to use the HandleError attibute and in the OnException I am adding the errors to Model. The major problem is how do I get those errors as a results in the Ajax Call?
There is not a great solution built in right now. Doing this correctly requires a client-side validation framework (because, to display the errors, you need to dynamically change the HTML page), and until recently, ASP.NET MVC has not had that. However, ASP.NET MVC 2 Preview 2 introduced client-side validation, so it's reasonable to presume that something might be built into the framework soon.
In the meantime, however, HandleErrorAttribute won't help you. HandleErrorAttribute only knows how to redirect to an error page, which is generally not what you want to do in response to a server-side validation error even with a "normal" POST, and certainly not with an AJAX post.
There really two different scenarios you need to handle:
Validation errors are not catastrophic failures; they are simply bad user data, which you should expect. You just need to get the information back to the page, so that the page can be marked up to tell the user how to fix their data.
You also need to handle catastrophic failures, like unanticipated exceptions. This is akin to what HandleErrorAttribute does, insofar as you can display a message to a user, but you cannot necessarily match that message up with specific fields on your page.
To handle the first scenario of error, you need to wrap the model state up into an object which will be parsable in JavaScript code; JSON is the obvious fit here. You then need to have JavaScript code on the client side which parses this object and marks up the form fields. This is easier if you tie into an existing client-side validation framework, which already contains code for marking up form fields.
To handle the second type of error, you can extend HandleErrorAttribute in order to provide JSON instead of HTML in the event of a catastrophic failure. Again, you will need to write JavaScript code that will be executed in the event of a failure -- jQuery's global ajaxError event is useful here -- that detects this structured error information you've created and display some sort of useful message to the user.
If all this sounds a bit involved, well, it is, which is why it may make more sense to wait and see what will be built-in when MVC 2 is finally released.