MVC 3: Test controllers VS integration tests - asp.net-mvc

I started with MVC quite recently because I heard that the major advantage of MVC is that it makes the application unit testable. After writing first unit tests I saw that it is not always simple to test controllers that have a lot of logic inside (send confirmation emails, use Session, context and other ASP Net statics). It takes me more time to write the unit test than the functionality and I am not convinced that this is useful.
I am tempted to move the business logic into a "Service" layer that eliminates of all ASP Net statics and which can be easily tested. Then to use Selenium for integration tests in order to test the whole functionality.
Did you got into the situation when testing an action is very complex (especially mocking the input and setting up environment)?
Did you find a good approach to have business logic in controllers. Or you found it better to use services and controllers code just relay on services calls?
In my opinion testing a controller is more equivalent to integration tests than to unit tests. What do you think about this?
Do you think that unit testing controllers has any advantage over integration tests?

I am tempted to move the business logic into a "Service" layer that
eliminates of all ASP Net statics and which can be easily tested. Then
to use Selenium for integration tests in order to test the whole
functionality.
This pretty much right here. If your controllers are complex then they need to be refactored. They shouldn't have any business logic at all. You can using a Mock framework to mock the service layer and test your controllers easily that way.
In my opinion testing a controller is more equivalent to integration
tests than to unit tests. What do you think about this?
I disagree with this. You are testing your controller to make sure it returns the appropriate response based on the input you give it. Supply an id that doesn't exist? Redirects to another page or returns a NotFound view. Model State is invalid? Returns the same view again, etc.

Did you got into the situation when testing an action is very complex (especially mocking the input and setting up environment)?
This happens when your controllers have lot of dependencies and they are tightly wired to them. Unless it is an existing code and bringing the changes to code creates more trouble you should loosely couple the dependencies through interfaces or abstract classes and that makes unit testable so easy. You should even use wrappers around Session, Cache and like objects.
As #Dismissile suggests that first you have to re-factor your controllers and then unit testing will be easy.
Did you find a good approach to have business logic in controllers. Or you found it better to use services and controllers code just relay on services calls?
Controllers are not the place to put business logic. All the business logic should be in the Model classes. The whole responsibility of the controller is to talk to the model and return a view, json or whatever back to the client. If you have complex business logic in the controllers you should move them to model classes.
Simply you should think about "Dump Views.. Thin Controllers.. Fat Models"!
In my opinion testing a controller is more equivalent to integration tests than to unit tests. What do you think about this?
Integration testing is totally different from Unit testing. In integration testing you have to setup the application and run the test cases against it. Here you are testing the behavior of the total application in every test scenario and not a single unit. Unit testing is all about testing the functionalities of methods in a class. Testing a class or method in unit testing should be independent of other classes or methods.
But the thing is when designing an application unit testing should be kept in mind else unit testing will become as difficult as integration testing and of course it's not unit testing at all.
Do you think that unit testing controllers has any advantage over integration tests?
Finding and fixing errors at unit level is so easy compared to the system level. So the answer is yes.
I think in your case you have an application that has controllers does more than what they have to do. So if you are thinking about unit testing so serious then you have to re-factor and loosely couple the dependencies wherever you need else there is no much gain in writing unit tests at all.

Related

How does moving the view controller's code to presenter make it easier to unit test in VIPER?

I have read in VIPER blogs that moving view controller's code to Presenter codes makes it easy to unit test. The reason given in the blogs was that the Presenter doesn't have any UIKit related code in it.
How does this make it easier to unit test. Can any one please explain this in detail? Or is there any other advantage of this apart from avoiding Massive View Controller problem?
The biggest problem in unit testing is how to mock something. You want to test a method but that method is calling 3 other methods and you don't want to test these 3 methods, therefore you want to mock them to return some fixed value.
This is pretty easy in languages like Javascript, where you can substitute a method on any object or in Objective-C where you can do the same (although with a bit more difficulty).
This is not easy in a language like Swift. Therefore Viper came with the idea to split view controller into units (e.g. Presenter, Interactor, View, Router) and every unit has its own protocol. Now to mock one the units you can just implement the protocol and use it instead of the real Presenter or View.
(you can actually use some tools to generate the mocks for you dynamically in tests)
That makes unit testing much much easier.
However note that unit testing UI is never easy. UI usually operates in terms that are difficult to unit test and unit testing UI almost always means that you will be duplicating a lot of your app code in unit tests. UI is more commonly tested via integration tests (e.g. automatic clicking and validating what is visible on the screen).
Viper is not a bad architecture. Separation of concerns is something that many programmers struggle with and it's not a bad idea to have strict architectural rules. With complex screens you still won't be able to avoid big controllers but at least you will be forced to move some code out of the controller.
Massive View Controllers are not a problem of the MVC pattern. They are a problem of bad separation of concerns and strict rules in Viper help to avoid that.

Is unit testing skinny controllers really necessary?

I am wondering if you guys do unit test your controllers and if it is common practise in a TDD environment.
What I have are skinny controllers that basically call on to the business layer for logic and data and then populate a local ViewModel to pass to the view.
I do unit test the business layer but I wonder if testing these skinny controllers still make sense or its really not necessary unless you have a fat controller with a lot of logic in it.
Please let me know your thoughts.
Thanks.
Creates a UT for class which all his doing is to forward calls from one point to another is not a good idea. The reason is quite simple: it's just not worth it.... you won't receive any benefit from those tests, more over you'll have to maintain those test over the time while you won't verify any behavior(just stracture...)
So how do I cover those units? the way is also simple; just test them as a part of something which use them.
Now back to the original question... The way I found to test my skinny controllers is through a component/integration tests. I start from the BL and when I have to coupled the BL with the controller I create a component/integration tests and then end the task with the controller implementation.
As a rule of thumb, I don't bother testing things that don't have any logic. Just calling another object hardly counts as logic IMO. Calling multiple other objects in a sequence where order matters is more debatable.
What I would do if I use an outside-in approach is TDD the controller by stubbing out its dependencies (business services, mappers, etc.) before I go one step further up the food chain and implement the real dependencies. But I rarely explicitly assert that dependencies should be called in a particular order. At the end of the day, these tests are more about design than proving correctness, and you could reasonably delete them once the whole graph of classes has been written.
Personally, no. But I don't normally do TDD either.
If you did write your tests first, you might as well leave them. They're not hurting anything.
If you didn't write your tests first, I agree that it doesn't make sense to add them afterwards, because at that point you're basically testing the MVC framework.

BDD with Cucumber and rspec - when is this redundant?

A Rails/tool specific version of: How deep are your unit tests?
Right now, I currently write:
Cucumber features (integration tests) - these test against the HTML/JS that is returned by our app, but sometimes also tests other things, like calls to third-party services.
RSpec controller tests (functional tests), originally only if the controllers have any meaningful logic, but now more and more.
RSpec model tests (unit tests)
Sometimes this is entirely necessary; it is necessary to test behavior in the model that is not entirely obvious or visible to the end-user. When models are complex, they should definitely be tested. But other times, it seems to me the tests are redundant. For instance, do you test method foo if it is only called by bar, and bar is tested? What if bar is a simple helper method on a model that is used by and easily testable in a Cucumber feature? Do you test the method in rspec as well as Cucumber? I find myself struggling with this, as writing more tests take time and maintaining multiple "versions" of what is effectively the same behaviors, which makes maintaining the test suite more time intensive, which in turn makes changes more expensive.
In short, do you believe there is there a time when writing only Cucumber features is enough? Or should you always test at every level? If you think there is a grey area, what is your threshold for "this needs a functional/unit test." In practical terms, what do you do currently, and why (or why not) do you think it's sufficient?
EDIT: Here's an example of what might be "test overkill." Admittedly, I was able to write this pretty quickly, but it was completely hypothetical.
Good question, one I've grappled with recently while working on a Rails app, also using Cucumber/RSpec. I try to test as much as possible at every level, however, I've also found that as the codebase grows, I sometimes feel I'm repeating myself needlessly.
Using "Outside-in" testing, my process usually goes something like: Cucumber Scenario -> Controller Spec -> Model Spec. More and more I find myself skipping over the controller specs as the cucumber scenarios cover much of their functionality. I usually go back and add the controller specs, but it can feel like a bit of a chore.
One step I take regularly is to run rcov on my cucumber features with rake cucumber:rcov and look for notable gaps in coverage. These are areas of the code I make sure to focus on so they have decent coverage, be it unit or integration tests.
I believe models/libs should be unit tested extensively, right off the bat, as it is the core business logic. It needs to work in isolation, outside of the normal web request/response process. For example, if I'm interacting with my app through the Rails console, I'm working directly with the business logic and I want the reassurance that methods I call on my models/classes are well tested.
At the end of the day, every app is different and I think it's down to the developer(s) to determine how much test coverage should be devoted to different parts of the codebase and find the right balance so that your test suite doesn't bog you down as your app grows.
Here's an interesting article I dug up from my bookmarks that is worth reading:
http://webmozarts.com/2010/03/15/why-not-to-want-100-code-coverage/
Rails has a well-tested codebase, so I'd avoid re-testing stuff that is covered in those steps.
For example, unless it is custom code, it is pointless to test the results of validations at unit and functional levels. I'd test them at the integration level though. Cucumber features act as specifications for your project, so it is good to specify that you need a validation for x and y, even if the implementation is a single line declaration in the model.
You usually don't want to have both Cucumber stories and RSpec controller specs/integration tests. Pick one (generally Cucumber is the better choice, except for certain special cases). Then use RSpec for your models, and that's all you need.
I test complex model/lib methods with rspec then the main business logic in web with cucumber, so I'm sure that the main features of the web will work 100%, then if I got more time and resources I test everything else.
Its easier to write simple specs for simple methods. Its much easier than writing cukes.
If you keep your methods simple - and keep your specs simple - by testing only the logic inside that method - you will find joy in unit testing.
If anything is redundant its cucumber tests. If you have well tested models and lib your software should work.
The purpose of Cucumber is not to run integration tests. Cucumber, an in general BDD, works as a communication platform, a way to improve the "talk" inside a big team of developers an non-developers that are developing big and complex software. BDD is very useful to communicate a model an its domain at the same level to everybody in the team, even if they don't know anything about computers.
If that is not your scenario, don't use cucumber, because you don't need it. Use rspec and capybara to test your JS code and your integration tests.

Could model unit tests be truly independent and how [ASP.NET MVC]

I am new to the whole unit testing stuff, so please excuse my lack of experience. I've read a lot of materials saying that no test should depend on others to do, i.e unit tests be completely independent form each other. Can you really do that in reality? I am having the following example: I have a few entity classes depending on each other, based on a certain database schema (I am using Linq- to SQL to generate them) Now, if I want to test each model class I have to build an object of the model class , build a test object of each of its dependencies, assign them to the object's properties and then persist the object before checking the context and asserting that it actually works.
This obviously makes it much harder to make tests that do not depend on each other, or do not run in a specific sequence (I do not an instance of type Content to be created before I have at least one instance of type ContentType) Dependency, at least on a model level is present and cannot be avoided.
Please, criticize me a lot, if you think that I am wrong. I want to learn.
P.S. Just to mention that I am working on an ASP.NET MVC app and testing with NUnit if that makes sense
Yes, you can really do this in reality.
The key to be able to isolate each unit is in writing loosely coupled code. Taking a dependency on LINQ to SQL (L2S) classes is not loosely coupled, which explains your problems.
You would be better off defining a set of interfaces behind which you can hide your L2S code. The Domain Model then works on those interfaces instead of directly on the L2S classes.
Yes, unit test should (and can) be independent. The problem you describe is about dependency. Dependency should be resolved using Dependency Injection frameworks (see AutoFac, Ninject projects).
The other thing is that your Database should be mocked using mock objects (see Moq, Rhino Mocks projects). You need to test all your code even if you database is disconected.
Other thing is that Unit test should test only one functionality not all your process.
What you describe here is not unit tests but integration test. Because the data model of your application is tightly coupled with the database your tests probably test the database functionality and not the "datamodel".
This is perfectly fine - just keep in mind that integration tests need setup (in your case database) and take longer to run.
You also probably have unit tests for your controllers that can be completely isolated from other components and do not need database to run, these are the unit tests you talk about.
If you do not test actual database functionality you can use fake/mock object to replace the external classes - in fact the tests created with the initial MVC project have an hand rolled fake objects along that do exactly that.
Another way to "isolate" your external dependencies is to warp the Linq2Sql code with your own class and fake these class calls using Mocking framework.

Should I mock my model in rails controller tests?

I am finding holes in my coverage because I have been mocking my models in controller examples. When I remove a model's method upon which a controller depends, I do not get a failure.
Coming from TDD in statically typed languages, I would always mock dependencies to the object under test that hit the database to increase speed. I would still get failures in the above example, since my mocks subclassed the original object. I am looking for best practices in a dynamic language.
Thanks.
UPDATE:
After getting a lot of conflicting opinions on this, it seems it boils down to which philosophy you buy into.
The Rspec community appears to embrace heavily stubbing dependencies to achieve isolation of the object under test. Acceptance tests (traditionally known as integration tests ;) are used to ensure your objects work with their runtime dependencies.
The shoulda / Test::Unit community appears to stay away from stubbing as much as possible. This allows your tests to confirm your object under test actually works with its dependencies.
This video summarizes this nicely: http://vimeo.com/3296561
Yes, in your controller examples, mock your models. In your model examples, test your models.
If you're using Mocha, the following should do it.
Mocha::Configuration.prevent(:stubbing_non_existent_method)
While writing unit tests, the whole aim should be test that unit only. Consider Model as one unit and cover it separately. Change in Model should not directly impact unit test coverage of controller.

Resources