On Sunday, April 15, 2012 at 9:23 PM, Rodrigo Rosenfeld Rosas wrote: > Em 14-04-2012 10:11, David Chelimsky escreveu: > > On Friday, April 13, 2012 at 2:09 PM, Rodrigo Rosenfeld Rosas wrote: > > > Hello old friends, I'm getting back to Rails and Ruby programming full > > > time again (Yay!) > > > > > > I've stopped doing Rails programming to work with Grails in 2009 after 2 > > > years working with Rails due to a better job offer. > > > > > > Since then I've changed my job once more, but still on Grails, but I > > > found a critical bug in Grails more than a week ago that didn't seem to > > > get much attention and is affecting the production system I maintain: > > > > > > http://jira.grails.org/browse/GRAILS-8994 > > > > > > As I couldn't work around that bug and I can't see myself reading the > > > Grails source code (a real mess!) I decided to take another approach that > > > would allow me to get back to Rails programming. > > > > > > I created a Devise / Warden strategy to send the cookies to the current > > > system and it will return me the current logged in user. So I can set up > > > Nginx to proxy some requests affected by the Grails bug to this new Rails > > > application. > > > > > > I've finished this action last Monday but when I was about to send all > > > the hard work to the server lots of my directories were suddenly gone > > > when I was using them. I still don't know what happened but I've replaced > > > my hard-drive just in case, but it means I had to do all over again :( > > > > > > Anyway, now I got it back to work but testing a single action (an > > > update/insert one) will take about a full second to run using RSpec and > > > FactoryGirl. > > > > > > I really don't like Grails but they had a great feature for unit testing. > > > They were able to mock their domain class (that is how they call their > > > models) in such a way that they can perform most of the operations you > > > can do on real objects. > > > > > > Of course it have another serious bug that will prevent me to use it in > > > lots of cases: > > > > > > http://jira.grails.org/browse/GRAILS-8854 > > > > > > But the idea is great as it works seamlessly like in a memory database. > > > > > > So, I'd like to be able to keep my tests easy to read but avoid touching > > > the database that much. > > > > > > But my controller spec rely on lots of the setting of ActiveRecord for my > > > models, like maximum calculations in before callbacks, custom foreign > > > keys and depends: :delete_all in some has_many associations. Also I do > > > also need a user object that Devise will accept on its sign_in helper > > > method. > > > > > > Is there any place I could read more about writing faster tests without > > > getting crazy writing so many mocks manually. For example, mocking a > > > Grails domain class in a unit test would be as easy as: > > > > > > @mock(User) > > > class UserTests... > > > > > > Then I'm able to do most operations using the Grails domain class API > > > using the User mock. > > > > > > Is there something like this for Rails and Rspec? Is there some way that > > > I could set up FactoryGirl to use those mocks instead of hitting the > > > database when I want to? > > > > > > Am I going in the wrong direction here? If so, what would be the right > > > direction? > > > > > > Thanks in advance. > > > > > > Glad to be part of the Ruby, Rails and Rspec community full-time again :D > > > > > > Cheers, > > > Rodrigo. > > You can use mock_model or stub_model to create model instances, or you can > > use FactoryGirl.build instead of FactoryGirl.create. Only mock_model will > > actually avoid db calls entirely (the others will still query for column > > names even if you don't save anything). > > > > Those techniques, however, don't help you with finders. You still have to > > stub any finders with the object generated by any of the aforementioned > > techniques: > > > > thing = mock_model(Thing) > > Thing.stub(:domain_specific_finder => [thing]) > > > > > I'm not sure what you're suggesting. For example, the first part of my > controller action looks like this: > > instance = Model.where(id: params[:id]).first_or_initialize(parent_id: > params[:parentId]) The controller is interacting with an ActiveRecord API on the model instead of a domain-specific-finder. I'd recommend wrapping this in a method on the model and then mocking _that_ method. > The spec starts with something like this: > > root = FactoryGirl.create :field, label: 'ROOT' > post 'action', parentId: root.id > > In the before/after Model callbacks there will be other kind of finders for > the same class. Think I'd need to see more of the code to comment on this. > How would you suggest me to change this block to use FactoryGirl.build and > mock Model? Use one or the other (they both serve a similar purpose). > Also, I couldn't find how to mock 'open' from 'open-uri', so I'm currently > mocking my controller's action: > > controller.should_receive(:clear_fields_cache).exactly(3).times # 1 creation > and 2 updates > > The action is implemented this way: > > require 'open-uri' > ... > private > def clear_fields_cache > open INTEGRATION_BASE_URL + 'clearModelCache', > 'Cookie' => authentication_cookie_string # includes JSESSIONID and > rememberMe > end > > But maybe it would be a great idea to check for the specific URL and cookie > handling and I could do so if I was able to mock the 'open' method from > 'open-uri'. Any ideas on how to do that? I use https://github.com/chrisk/fakeweb for this sort of thing. It operates more like a stub than a message expectation. > > It's not pretty, but it's the best way I know of to get what you're after. > > I started a lib called stubble a few years back that attempted to address > > this more holistically (https://github.com/dchelimsky/stubble) but I never > > released it as a gem because there were just too many different ways to > > access model data via the ActiveRecord API and they don't all flow through > > a single part of the codebase that we can override in an extension. > > > > I agree with you. I've taken a look at the library but as you can see I'm > using the new 'where' API and this probably will keep changing each new AR > release... This is exactly why I like to wrap finders in domain-specific methods on the model :) > Also, in Grails case, the mocked domain classes are maintained alongside with > the real classes, so there is little chance of them getting out of sync. But > of course the mocks have some limitation, like not being able to deal with > custom SQL fragments: > > http://grails.org/doc/latest/guide/testing.html#unitTestingDomains > > Other than that there are also some bugs when dealing with association ids. > > I never thought it would be easy to have something like this for ActiveRecord > but once there is a long time since I last often worked with Rails, things > might have changed ;) > > Thank you a lot for your input and glad to be talking to you again :) > > Cheers, > Rodrigo. > _______________________________________________ > rspec-users mailing list > rspec-users@rubyforge.org (mailto:rspec-users@rubyforge.org) > http://rubyforge.org/mailman/listinfo/rspec-users > >
_______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users