UI Testing MVC with WatiN and injecting parameter to controller - asp.net-mvc

First off, I may be barking up the wrong tree with this, so please correct me if I am wrong.
That said, I am trying to write sme UI unit tests that use WatIn. I am only working on a subset of the UI at present.
I have a controller called Product along with its associated views.
the Controller takes in a ProductRepository via the constructor.
What I would lie to do is to test that different product categories are rendered correctly, in different tests, so I need to pass in some kind of stubbed or mocked repository into my code.
My test is set up along the lines of;
using (var ie = new IE("http://localhost:2904/Product"))
{
...
}
So how do I pass in a repository to my controller that will provide the appropriate product? Once I have called the using statement, my system has launched the browser, so that is too late. But until the browser is launched, then the controller doesnt exist, so I can't inject in the appropriate repository.
Or have I fundamentally got this wrong, and I can only use WatiN against my database, and I need to program it to select a member of each type of product from the db, adn test that way?

I think, as you suggesting, you pick the wrong end of the problem. If I understand correctly, you don't need UI test and Watin but rather integration tests. I would suggest to create instance of controller, inject repositories as needed and mock other dependencies. Than you can switch repositories and so.
In UI tests you test your whole application from the top of UI down to database so it's hard to change behavior or mock some parts. Do you really need to test your functionality with UI? Wouldn't be better to test it only in controller or it's not option for your case?
Seems ok or I misunderstand you completely?

Related

What are the next steps for unit testing with dependency injection?

I'll start out by saying I'm a huge fan of unit testing. I've been using it for a couple of years. So far, though, my use has been limited to ensuring engineering calculations are performed correctly, strings are formatted properly, etc. Basically, testing my work on class libraries to be consumed in other projects.
Now, I want to branch out and apply unit testing to my work on ASP.NET Web API. At this point I have my controller written and working with Ninject. Although I'm using Ninject, I'm still not 100% sure why I'm doing it and haven't seen the benefits yet.
On to my question, what are the next steps for unit testing my Web API controllers? What should I do next and when will I reap the benefit of using Ninject?
Next, you could create fake data (or a mock) that your controller can return to your views. This will allow you to do front end development without having to complete the back end implementation.
The benefit of using Ninject is that you can create mock objects for testing purposes. By injecting the interface instead of the concrete implementation you can easily switch between the real and mock object. To do this you simply change which one should be injected in the Ninject bindings. Using something like Rhino Mock in conjunction with Ninject you can write and test your code (controllers, views, etc) without having to fully implement all of the functionality. When you're ready to implement a mocked piece of functionality, you don't have to rewrite your code to accommodate the changes, you simply update your bindings. Now real data will display on your pages instead of the mocked data you created previously.

Unit testing an ASP.NET MVC 3 application

We have an ASP.NET WebForms application that we're going to convert to be ASP.NET MVC application - one of the reasons is so that we may take full advantage of Unit Testing and TDD.
Our current WebForms application makes heavy use of HttpModules. We're currently debating whether we should stick with HttpModules or use Global Filters (any advice here would be great).
However, with my few "hello world" test MVC applications, I've not worked out how to get the HttpModule (or indeed the Global Filter) code to fire when Unit testing.
Maybe I'm wrong, but it seems to me that I need this to be part of my unit-testing (integration testing) otherwise it can't be a true representation of what's going on in my Production code.
Any guidance would be most welcome.
Thanks
Griff
PS - I added the following after the initial responses to my question.
Simple made-up Use Case
In Production
Browser makes a Request for a Controller Method
HttpModule fires (or Global Filter) - this sets a static Guid property to have a value.
The controller method takes this Guid value and uses it in its subsequent logic
Correct result is then returned to the browser
In Unit Testing
Unit test calls the same Controller Method
The HttpModule (or Global Filter) does not fire - the static Guid property has a value of Guid.Empty
The controller method takes this Guid value, but throws an error because it was an Empty Guid
Unit test fails
My thoughts are:
if a Controller relies upon an HttpModule (or Global Filter) to run first, then the HttpModule is a dependency and therefore the results of it's action must be Stubbed for the test to be a true Unit Test.
If the test is to include the effect of the HttpModule (or Global Filter) to run, then this would be an Integration test (though it's still not clear yet how to get the HttpModule or Global Filter to run as part of the Integration test)
The HttpModule (or Global Filter) should have their own set of Unit Tests
I think this is the approach I'll take, but if anyone could suggest how I get my Integration test (as described above) to work then I'd be most grateful.
The problem as I see it is that my TEST project becomes the "start up" project when running my tests, so the HttpModules (defined in the ASP.NET MVC's web.config file) and the Global Filters (defined in the ASP.NET MVC's global.asax file) will not run because the web.config and global.asax files are not executed. So the question remains: how do I get these to run in my Integration test?
Thanks everyone
Griff
You shouldn't be testing to check if the global filter fires or not. The mechanism that fires the code isn't your code, it's part of the framework so the framework team is supposed to test that.
Instead you should simply be testing to make sure that the global filter has been applied.
Whether or not to call a HttpModule or Global Filter is handled by the Framework. You shouldn't be worried about Unit Testing things that are handled by the Framework. Your Unit Tests should only test that your HttpModule or Global Filter behave properly when called.
I would mock the http modules and repositories to unit test the controllers and services, in my view that's how you unit test. the global filters and httpmodules you can test it with end to end tests. Hope it helps.

How do I test that Asp.Net MVC Views are rendered without exceptions?

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

Mocking a Controller dependency with Moq using specflow

I am new to specflow and a have a doubt about how to mock my
controller dependencies.
For instance I have a UserController class which depends on my
UserRepository class that a pass to the controller class on its
constructor.
So using Moq I am doing something like this:
var mock = new Mock<UserRepository>();
mock.Setup(m => m.ListAll()).Returns(new List<User>());
var browser = new IE(string.Format("http://localhost:4265/{0}",
username));
But my controller is not using the mocked object, how should I do
that?
Thanks
You are mixing three (atleast) test framework, which ofcourse is cool, but you should probably stop and consider what it is you want to test.
Watin is good for testing your UI as it controls a browser instance. I find it good at making regression tests http://en.wikipedia.org/wiki/Regression_testing
Specflow is great as well - personally i like to use it for closing the gap between business developers and (us) software developers as we can actually define requirements in terms we both understand (and probably other parts of the organization as well) I don't want to start a flame war, but it can introduce more problems than it solves, unless you focus on its real values. We use this at work by testing the service layer (one layer below the controllers in the presentation layer) and we actually only mock the database, external services and file system etc - which makes our specflow tests some kind of integration tests.
Moq is a mocking framework and can ofcourse be used in any kind of tests (like i just let it slip we do) but this is such a great tool for unit testing.
So to return to your question. If you want to make one test to find all your bugs, you're in trouble ;) I know you don't want that - that was just a silly suggestion i made - but really, if you just want to do integration tests (tests running from the UI down through several layers/dependencies) you could easily mix different testing frameworks like you are now, but then why mock the user repository? Is that because you don't want to hit the database?
Anyways one way to do the integration test you seem like you want would be to configure your solution to use a mock - or perhaps a stub would do (create a fake userrepository that returns the data you want to test with) - you should use a Dependency framework like Unity, Ninject or structure map (boy let's not start a war about what framework to use) and have the test url Watin is using launch your site using a configuration with the fake/mock repositories.
You could on the other hand do unit testing on your controllers, services etc. You might even want to try out TDD but that's a whole other chapter i can't cover here!
You are not doing anything with the mock to inject it into your controller. Your controller needs to be given the user repository in order for it to be used.
Also you need to accept more answers.

Where to instantiate Data Context (adapter, connection, session, etc) in MVC?

We are building an ASP.NET MVC site, and I'm struggling with where to define a connection to best enable unit testing (I use 'connection' generically - it could be a session, a connection, an adapter, or any other type of data context that can manage transactions and database operations).
Let's say we have 3 classes:
UserController
UserService
UserRepository
In the past, we'd do something like this within a method of the UserService:
Using (ISomeSession session = new SomeSession())
{
session.StartTransaction();
IUserRepository rep = new UserRepository(session);
rep.DoSomething();
rep.Save();
session.Commit();
}
However, it wasn't really possible to unit test this since the dependency on SomeSession wasn't injected. However, if we use D.I. to inject the dependency in the UserService, the session hangs around for the life of the UserService. If there are multiple services called from the UserController, each could have sessions just hanging around until the UserController is garbage collected.
Any thoughts on how to better manage this? Am I missing something obvious?
Edit
Sorry if I wasn't clear - I understand that I can use Dependency Injection with the Session/Data Context, but then it's being maintained over the life of the Service class. For any longer-running actions/methods (i.e. let's say the service is being called by a batch process), this could lead to a lot of open sessions for no reason other than adding testability.
As RichardOD correctly observed, you can't use live database connections for writing unit tests. If you are doing it, then you are integration testing.
I have separate implementations for my repository interface, one real repository, and one fake repository for unit testing. The fake repository works on a generic list instead of a real data context. I am using DI (with Ninject to make things more comfortable, but you can do it just as well by hand) to inject the correct repository.
There are only very few instances in which I am unit testing with real connections, but that's a unit test for my repository class, not for any controller, UI or Business layer objects.
Edit: With the comment you added, I think I now understand what you were actually asking for. Funny you'd ask something about that, since I worked on the very same subject last week :-)
I instantiate the data context inside a very thin wrapper and put the context inside the HttpContext.Current.Items dictionary. This way, the context is global, but only for the current request.
Still, your question's subject is highly misleading. You were asking "where to instantiate a data context for unit testing" and the answer is that you usually don't. My unit tests still operate on fake repositories.
The easiest way is to have a Connectionstring that you define in web.config for development and production. For Unittests you define it in app.config of your Testproject.

Resources