How would you go about testing partial, RSpec? - ruby-on-rails

Lets say I have a very complicated view with a very complicated test spec.
I would like add another feature to it and I would like to drive the development with RSpec.
I would like to add contacts to Employee class.
Somewhere in the employee.html.erb I add the line:
#lots of data rendered so far
<%= render #employee.contacts %>
#even more here
At the moment I don't really know what _contact.html.erb partial needs to look like. To test it directly from my main view spec for employees, show.html.erb_spec.rb, I would have to do a lot of set up populating or mocking different database employee is build from(projects, departments etc.).
All I need to test for now is that partial, I don't care about departments, projects and other things this employee currently belongs to and I don't want to spend my time on mocking them all up. I will probably add it to my main spec later on and create everything needed to test the entire view but not just jet.
Do you have any technique or way for creating an instance of Employee, adding a few Contacts to it, and testing the view for just the partial?
Without worrying about all the other things the Employee is built from.
UPDATE FOR IGEL ANSWER:
I agree with you, and testing for expect(...).to receive(:render) is 100% enough for request spec and I would go no further if I already had a partial template.
I just wanted to go extreme and drive my div's and span's through RSpec. Not testing for behaviour of new feature but it look. Do you suggest its not worth it?
I don't test views(structure) at all but I have seen a few documents like Rails Tutorial where Michael is not only testing behaviour but as well structure. I thought I'll give it a go:)

The correct answer is to avoid very complicated views. If there is almost no logic in the view, then there is maybe no need to test it. Extract the logic into presenters, that way it's much easier to test. I don't test my views with view tests, because maintaining them it usually not much fun. Some feature specs give me enough security here.
If you still want to test it, you would probably expect that render was called with the expected arguments:
expect(view).to receive(:render).with(#employee.contacts)
Not sure if the view is available via view.
PS: Don't just avoid to write complicated views, avoid complicated code. This is really hard, but also absolutely worth the time. Almost every developer can hack together something probably working, but creating something easy to understand and to change will help everybody including your future you. Code is read ten times more often than it is written/changed, so we have to optimize for that.
I didn't have time to write a short letter, so I wrote a long one instead.
-- Mark Twain

Related

Rails and Testing, why testing controllers is not enough?

I was wondering, as testing a controller in rails run the associated views (even if not shown) and integrate many models concerns (by saving, updating,...), testing controller should be almost enough for all applications near enough of CRUD classical architecture. Am I wrong?
Furthermore, views can be tested in the browser, as eyes can be quicker to check than describing everything in a test (and they can achieve CSS control too.)
Thank you for your point of view!
PH
Testing only your controllers will tell you that, broadly, your app is working, at least in terms of not 500'ing or whatever. But can you be sure that it is doing the exactly correct thing? If all you need to test is standard resourceful behaviour like "given params[:id], is the record with id <params[:id]> loaded?" then just testing the controller might be enough.
But, you will inevitably add more complicated behaviour into your models. In this situation, your controller may set some variables or something, without raising an error, by calling a model method. At this stage, it's much cleaner to test the model method directly, to make sure that given a particular set of conditions, it does the right thing.

Structure of BDD tests

I'm digging into Capybara and rspec, to move from TDD to BDD.
My generators make a whole lot of directories and spec tests,
with directory structure similar to this:
spec
controllers
models
requests
routing
views
I think that most of this is TDD rather than BDD. If I read here:
"A great testing strategy is to extensively cover the data layer with
unit tests then skip all the way up to acceptance tests. This approach
gives great code coverage and builds a test suite that can flex with a
changing codebase."
Then I figure that things should be quite different
something on the lines of:
spec
models
acceptance
Basically I take out controllers, requests, views, and routing to just implement tests as user case scenarios in the acceptance directory with Capybara, Rspec.
This makes sense to me, though I'm not sure if this is the standard/common approach to this.
What is your approach?
Thanks,
Giulio
tl;dr
This is not a standard approach.
If you only test models and feature specs... then you miss out on the bits in the middle.
You can tell: "method X broke on the Widget model" or you can tell "there's something wrong while creating widgets" but you have no knowledge of anything else.
If something broke, was it the controller? the routing? some hand-over between the two?
it's good to have:
extremely thorough testing at the model-level (eg check every validation, every method, every option based on incoming arguments)
rough testing in the middle to make sure sub-systems work the way you expect (eg controllers set up the right variables and call the right templates/redirections given a certain set of circumstances)
overall feature testing as smoke-tests (eg that a user can go through the happy path and everything works the way they expect... that if they input bad stuff, that the app is throwing up the right error messages and redisplaying the forms for them to fix the problem)
Don't forget that models aren't the only classes in your app.. and all classes need some kind of testing. Controllers are classes too. As are form and service objects, mailers, etc.
That said - it's common to consider that view-tests are going overboard. I'm also not keen on request-tests our routing test myself (unless I have something complex which I want to work right, eg lots of optional params in a route that map to interesting search-patterns)

Modifying Rails: How do advanced users find out what needs to be changed?

I've been using Rails for a few months now, and I'm quite comfortable writing up a project & manipulating Rails to my needs, etc.
Recently I've been trying to get a little more advanced, so I've attempted to modify/add to the existing rails codebase: add new form helper methods, add a responds_to :pdf method, etc...and I've been having a lot of problems.
The difficulty is learning which code I need to modify; where that code is located, and how to ensure I don't miss related code in other files. I'm guessing there's a way people learn to do this, but at the moment I'm mostly just guessing-and-hoping.
I guess my question is, how do Rails folks go about learning where the code they need to modify is edited & the approach to editing it? It seems like it's just something you need to know from prior familiarity, but I'm guessing there has to be a simple method for understanding where (and what) to edit.
Any ideas appreciated...cheers
I highly recommend Jose Valim's Crafting Rails Applications
You go through advanced projects, building out the types of engines and customizations that will take you to the next level in your Rails development.
From the site:
This book will help you understand Rails 3’s inner workings, including
generators, template handlers, internationalization, routing, and
responders.
What you are asking for is how MVC works. Basicly you can say:
1.) Put logic to the model! The model is the pivot everything turns around.
2.) The Controller is a middleman between the model and the view. You dont put any logic here that isnt related to selecting data from the database that should be displayed in the view. If you use one selection logic more than once create a scope in the Model and use it in the Controller.
3.) The View is only there to display things! You dont put any logic here! All the logic comes from the model and the data comes from the controller. The only logic your using here are loops through arrays of data that should be displayed.
Then you have some things missing. If you have a task that is related to an external service like lets say a SOAP Service you write a class for that too! Just whithout using ActiveRecord::Base inheritance like its generated by the scaffolder. You can call this Class in other models. Dont put this to the controller or copy the code in every class that needs it! Stay DRY (Dont Repeat Yourself). Just write a class for it and include it in the other models!
Another thing thats a Database basic: Dont store data that could be calculated from other fields from the database! You can add methods that calculate the stuff you need but dont start with duplicates.

Ruby on Rails - Best practice / method for loading side column content/blocks

I am developing a community / news article website where there is a side column with different "blocks" on nearly all pages. In these blocks is "Recent Articles (showing five most recent articles)," "Recent Blogs," "Recent Comments," you get the drift.
When I started out building the application, I wasn't real sure where to put the controller code (say, to call #recent_articles = Article.where...etc). I didn't think it could go into the Articles controller, because it's not always the Articles controller being called. So I thought it would work best in the application controller, as most content on the site would be calling this. I put "#recent_content" into the application controller, did a :before_filter to load it.
You might see the flaw in this. As I'm getting better with Rails, I went back to refactor as the site was loading horribly and sure enough, all my logic in the application controller defined by before_filter was being loaded on every action, no matter if it was needed or not. (The site sped up dramatically when I cleaned house on the application controller).
My mistake is realized, but I still need to define the instance variables for #recent_articles, #recent_blogs, etc somewhere, so they load up only when needed. Granted I'll be eventually caching the site content when it goes into production, but I want to be a good Rails programmer here.
So here is my question...exactly how would you handle this situation and where would you put the logic? I can think of two ways, not sure which one is better...
The first way...I took a look at a project from another Rails developer and I noticed he was doing odd things like this by creating files in the /lib folder. For example, defining a method for page meta tags or active menu states. I honestly haven't messed with the /lib folder before, figuring most of my stuff should stay in the /app folder.
The second way...seems to me like helpers might seem the way to go. Maybe I could define a "recent_articles" helper, call my #recent_articles instance variable in there, then render and pass the results to a view file in my shared folder.
Overall, which one of these ways is the better way to go, either from a performance or best-practices viewpoint? Or is there a better way of doing this that I'm unaware of?
Whenever there are many models that can call a particular method, i would probably use a module. I think that is what you are talking about in your first idea, since /lib is where modules are placed.
You can use helpers as well, but it's a good idea to keep logic out of helpers, only in models if possible. Helpers should be just used as a way to present data, they are part of views. If logic is added, then something is wrong :)
Make sure that you do not have logic in your controllers as well. I would be doing the same things in the beginning, but it's really a bad idea. Instead, put everything in your models, or maybe a module if they seem to be used by many other models.
Hope that helps you a bit :)

My RoR application is almost finished. What should be done now?

I am running Ruby on Rails 3 and I have almost completed my application. All controllers, views and models are implemented for my needs (login function, logout function, new user creation function, mailer, ...). I also created a layout (mostly using sub-layouts and'content_for') and implemented some AJAX functions.
So, what should I do now (except the deployment) in order to improve \ complete my application?
One my doubt, for example, is whether to use view files as they are or create a dedicated controller only to handle pages. That is, is it good to create a "User page" that renders 'views/user/show.html.erb' and 'views/user/edit.html.erb' templates in one page instead of using views files separately calling those using link_to?
Of course there are other doubts that, maybe, I don't know yet. I would appreciate if you could share your and make suggestions.
Is this something that you're going to keep and maintain for a while? If so my advice would be to test it. Look into Test::Unit or RSpec (which I prefer) and test your models and controllers. You'll no doubt want to go back and refactor, and it'll be a lot easier if you have a healthy set of tests validating that everything still works as expected.

Resources