Hi David, I''m giving a try to RSpec after we meet each other on Rails Summit Latin America and I must admit I''m enjoying using rspec/machinist/faker. Since I have not written any controllers yet, I hadn''t taken a chance to try webrat. But there is a situation that I would like some feedback on how to deal with it. When registering new users, they will input their e-mail and a message will be sent for them to confirm their addresses and continue registering. I use something like: MailNotifier.deliver_email_confirmation_message :confirmation_url => url_for(:controllers => ''users'', :action => ''continue_register'', :user => @user.id, :token => @user.confirmation_token) And the routes are set to '':controller/:action'', so that the url would translate to ''/users/continue_register?user=2&confirmation_token=asdf987asf''. The problem is that Ruby 1.8 will not maintain any specific order for the parameters. (The application is hosted in a shared server at hostingrails.com, which hosts Ruby 1.8) I know that I could add a route to generate ''/users/continue_register/2/asdf987asf'' instead, but I would still like to know what would be the alternatives. How could I verify that the delivered message contains a correct url? I know that I should follow the url in an acceptance test, but I''m just trying to test that the message is been correct generated, in a unit test. Please, let me know if I missed something conceptually while testing this situation. Thanks for RSpec and the tips about machinist, faker and webrat. Just one more doubt. When using machinist, is it possible to ignore the blueprint while calling ''make'' on an ActiveRecord class? I had to create a named blueprint reseting all fields set by the blueprint. It was nice to meet you. Best Regards, Rodrigo. __________________________________________________ Fa?a liga??es para outros computadores com o novo Yahoo! Messenger http://br.beta.messenger.yahoo.com/
On Oct 27, 2009, at 8:21 AM, Rodrigo Rosenfeld Rosas wrote:> Hi David, I''m giving a try to RSpec after we meet each other on > Rails Summit Latin America and I must admit I''m enjoying using rspec/ > machinist/faker. > > Since I have not written any controllers yet, I hadn''t taken a > chance to try webrat. > > But there is a situation that I would like some feedback on how to > deal with it. > > When registering new users, they will input their e-mail and a > message will be sent for them to confirm their addresses and > continue registering. > > I use something like: > > MailNotifier.deliver_email_confirmation_message :confirmation_url => > url_for(:controllers => ''users'', :action => > ''continue_register'', :user => @user.id, :token => > @user.confirmation_token) > > And the routes are set to '':controller/:action'', so that the url > would translate to ''/users/continue_register? > user=2&confirmation_token=asdf987asf''. > > The problem is that Ruby 1.8 will not maintain any specific order > for the parameters. (The application is hosted in a shared server at hostingrails.com > , which hosts Ruby 1.8) > > I know that I could add a route to generate ''/users/ > continue_register/2/asdf987asf'' instead, but I would still like to > know what would be the alternatives.Oi Rodrigo, There''s no great alternative that I know of. I''ve always just grabbed the URL using a regexp and then broken it up. Something like this: text.should =~ /http:\/\/test\.host\/users\/continue_register\?([^\s]*)/ query_string = $1 query_string.should =~ /user=2/ query_string.should =~ /confirmation_token=asdf987asf/ You could also use Rack::Utils.parse_query to convert the query_string to hash, or capture the entire url and use the route_to matcher: text.should =~ /(http:\/\/test\.host\/users\/continue_register\?[^\s]*)/ {:get => $1}.should route_to( :controllers => ''users'', :action => ''continue_register'', :user => @user.id, :token => @user.confirmation_token ) I don''t love either of those - I''d sooner change the implementation to something deterministic, but that''s me :)> > How could I verify that the delivered message contains a correct > url? I know that I should follow the url in an acceptance test, but > I''m just trying to test that the message is been correct generated, > in a unit test. > > Please, let me know if I missed something conceptually while testing > this situation. > > Thanks for RSpec and the tips about machinist, faker and webrat. > > Just one more doubt. When using machinist, is it possible to ignore > the blueprint while calling ''make'' on an ActiveRecord class? I had > to create a named blueprint reseting all fields set by the blueprint.I don''t know of a way of to do this, but why do you need to? You may want to look at a couple of other libraries like Fixjour, Fixture Replacement and Factory Girl - they serve the same function as Machinist, but don''t (afaik) add methods to ActiveRecord::Base.> It was nice to meet you.O prazer foi meu. Tchau, David> > Best Regards, > > Rodrigo.
Em 27-10-2009 15:17, David Chelimsky escreveu:> On Oct 27, 2009, at 8:21 AM, Rodrigo Rosenfeld Rosas wrote: > >> Hi David, I''m giving a try to RSpec after we meet each other on Rails >> Summit Latin America and I must admit I''m enjoying using >> rspec/machinist/faker. >> >> Since I have not written any controllers yet, I hadn''t taken a chance >> to try webrat. >> >> But there is a situation that I would like some feedback on how to >> deal with it. >> >> When registering new users, they will input their e-mail and a >> message will be sent for them to confirm their addresses and continue >> registering. >> >> I use something like: >> >> MailNotifier.deliver_email_confirmation_message :confirmation_url => >> url_for(:controllers => ''users'', :action => ''continue_register'', >> :user => @user.id, :token => @user.confirmation_token) >> >> And the routes are set to '':controller/:action'', so that the url >> would translate to >> ''/users/continue_register?user=2&confirmation_token=asdf987asf''. >> >> The problem is that Ruby 1.8 will not maintain any specific order for >> the parameters. (The application is hosted in a shared server at >> hostingrails.com, which hosts Ruby 1.8) >> >> I know that I could add a route to generate >> ''/users/continue_register/2/asdf987asf'' instead, but I would still >> like to know what would be the alternatives. > > Oi Rodrigo, > > There''s no great alternative that I know of. I''ve always just grabbed > the URL using a regexp and then broken it up. Something like this: > > text.should =~ /http:\/\/test\.host\/users\/continue_register\?([^\s]*)/ > query_string = $1 > query_string.should =~ /user=2/ > query_string.should =~ /confirmation_token=asdf987asf/ > > You could also use Rack::Utils.parse_query to convert the query_string > to hash, or capture the entire url and use the route_to matcher: > > text.should =~ /(http:\/\/test\.host\/users\/continue_register\?[^\s]*)/ > {:get => $1}.should route_to( > :controllers => ''users'', > :action => ''continue_register'', > :user => @user.id, > :token => @user.confirmation_token > ) > > I don''t love either of those - I''d sooner change the implementation to > something deterministic, but that''s me :)David, thank you very much for your feedback, although not ideal they are good approaches. I understand your point of view in changing to something deterministic and I was thinking in doing that, at first. But I would like to know if there was a gotcha that I couldn''t figure it out. I need to choose between clean code in the implementation or in the test... Using a deterministic approach would make the test clearer, while using url_for with Ruby 1.8 would make the implementation clearer... That is why I was thinking in creating a route to achieve both, but it would exist only to make both clearer and could cause some confusion while reading routes.rb... The first approach you presented is clearer, but wouldn''t detect a problem that I noticed when testing my mailer. I was using RedCloth''s textilize, thinking that it would generate a link (which actually auto_link does) and I was testing if the link was contained in the body. The first approach wouldn''t detect that the url was wrong, like "?user=1&token=abc". The second approach goes against Ruby way, in my opinion... :) Too many code to test a single statement... Another approach would be something like: Regexp.new(''http://test.host/users/continue_register\?''+([''([^\s]+)'']*2).join(''\&'')). match(email.body).to_a[1..-1].to_set.should = ["user=#{@user.id}", "token=#{@user.activation_token}"].to_set where the first line could be replaced, in this case, with: Regexp.new(''http://test.host/users/continue_register\?([^\s]+)\&([^\s]+)''). although I would prefer another matcher to exist: match(email.body).to_a[1..-1].should have_same_elements(["user=#{@user.id}", "token=#{@user.activation_token}"]) But the problem with this approach is that I would probably need to write another test for testing this test ;)> >> >> How could I verify that the delivered message contains a correct url? >> I know that I should follow the url in an acceptance test, but I''m >> just trying to test that the message is been correct generated, in a >> unit test. >> >> Please, let me know if I missed something conceptually while testing >> this situation. >> >> Thanks for RSpec and the tips about machinist, faker and webrat. >> >> Just one more doubt. When using machinist, is it possible to ignore >> the blueprint while calling ''make'' on an ActiveRecord class? I had to >> create a named blueprint reseting all fields set by the blueprint. > > I don''t know of a way of to do this, but why do you need to?Usually, for most tests, I need to create active users. Only for testing the registering process, I need another structure. Active users must have login, name, email and password. Inactive users would only have email.> You may want to look at a couple of other libraries like Fixjour, > Fixture Replacement and Factory Girl - they serve the same function as > Machinist, but don''t (afaik) add methods to ActiveRecord::Base.Actually, I''ve taken a look at Factory Girl, but prefered Machinist, which is awesome. I''ll take a look at Fixjour and Fixture Replacement. Do they have a blueprint-like feature? I have no problem in creating methods in ActiveRecord::Base. I just wanted to call something like: User.make_without_blueprint(:email => ''test at test.com'', :active => ''false'') Thank you for your feedback, Rodrigo. __________________________________________________ Fa?a liga??es para outros computadores com o novo Yahoo! Messenger http://br.beta.messenger.yahoo.com/
On Oct 27, 2009, at 6:48 PM, Rodrigo Rosenfeld Rosas <lbocseg at yahoo.com.br > wrote:> Em 27-10-2009 15:17, David Chelimsky escreveu: >> On Oct 27, 2009, at 8:21 AM, Rodrigo Rosenfeld Rosas wrote: >> >>> Hi David, I''m giving a try to RSpec after we meet each other on >>> Rails Summit Latin America and I must admit I''m enjoying using >>> rspec/machinist/faker. >>> >>> Since I have not written any controllers yet, I hadn''t taken a >>> chance to try webrat. >>> >>> But there is a situation that I would like some feedback on how to >>> deal with it. >>> >>> When registering new users, they will input their e-mail and a >>> message will be sent for them to confirm their addresses and >>> continue registering. >>> >>> I use something like: >>> >>> MailNotifier.deliver_email_confirmation_message :confirmation_url >>> => url_for(:controllers => ''users'', :action => >>> ''continue_register'', :user => @user.id, :token => >>> @user.confirmation_token) >>> >>> And the routes are set to '':controller/:action'', so that the url >>> would translate to ''/users/continue_register? >>> user=2&confirmation_token=asdf987asf''. >>> >>> The problem is that Ruby 1.8 will not maintain any specific order >>> for the parameters. (The application is hosted in a shared server >>> at hostingrails.com, which hosts Ruby 1.8) >>> >>> I know that I could add a route to generate ''/users/ >>> continue_register/2/asdf987asf'' instead, but I would still like to >>> know what would be the alternatives. >> >> Oi Rodrigo, >> >> There''s no great alternative that I know of. I''ve always just >> grabbed the URL using a regexp and then broken it up. Something >> like this: >> >> text.should =~ /http:\/\/test\.host\/users\/continue_register\?([^ >> \s]*)/ >> query_string = $1 >> query_string.should =~ /user=2/ >> query_string.should =~ /confirmation_token=asdf987asf/ >> >> You could also use Rack::Utils.parse_query to convert the >> query_string to hash, or capture the entire url and use the >> route_to matcher: >> >> text.should =~ /(http:\/\/test\.host\/users\/continue_register\?[^ >> \s]*)/ >> {:get => $1}.should route_to( >> :controllers => ''users'', >> :action => ''continue_register'', >> :user => @user.id, >> :token => @user.confirmation_token >> ) >> >> I don''t love either of those - I''d sooner change the implementation >> to something deterministic, but that''s me :) > > David, thank you very much for your feedback, although not ideal > they are good approaches. > > I understand your point of view in changing to something > deterministic and I was thinking in doing that, at first. But I > would like to know if there was a gotcha that I couldn''t figure it > out. I need to choose between clean code in the implementation or in > the test... > > Using a deterministic approach would make the test clearer, while > using url_for with Ruby 1.8 would make the implementation clearer... > That is why I was thinking in creating a route to achieve both, but > it would exist only to make both clearer and could cause some > confusion while reading routes.rb... > > The first approach you presented is clearer, but wouldn''t detect a > problem that I noticed when testing my mailer. I was using > RedCloth''s textilize, thinking that it would generate a link (which > actually auto_link does) and I was testing if the link was contained > in the body. The first approach wouldn''t detect that the url was > wrong, like "?user=1&token=abc". > > The second approach goes against Ruby way, in my opinion... :) Too > many code to test a single statement... > > Another approach would be something like: > > Regexp.new(''http://test.host/users/continue_register\?''+([''([^\s]+)''] > *2).join(''\&'')). > match(email.body).to_a[1..-1].to_set.should => ["user=#{@user.id}", "token=#{@user.activation_token}"].to_set > > where the first line could be replaced, in this case, with: > Regexp.new(''http://test.host/users/continue_register\?([^\s]+)\&([^\s]+)'' > ). > > > although I would prefer another matcher to exist: > match(email.body).to_a[1..-1].should have_same_elements(["user=# > {@user.id}", "token=#{@user.activation_token}"]) > > But the problem with this approach is that I would probably need to > write another test for testing this test ;) > >> >>> >>> How could I verify that the delivered message contains a correct >>> url? I know that I should follow the url in an acceptance test, >>> but I''m just trying to test that the message is been correct >>> generated, in a unit test. >>> >>> Please, let me know if I missed something conceptually while >>> testing this situation. >>> >>> Thanks for RSpec and the tips about machinist, faker and webrat. >>> >>> Just one more doubt. When using machinist, is it possible to >>> ignore the blueprint while calling ''make'' on an ActiveRecord >>> class? I had to create a named blueprint reseting all fields set >>> by the blueprint. >> >> I don''t know of a way of to do this, but why do you need to? > > Usually, for most tests, I need to create active users. > > Only for testing the registering process, I need another structure. > > Active users must have login, name, email and password. > > Inactive users would only have email. > >> You may want to look at a couple of other libraries like Fixjour, >> Fixture Replacement and Factory Girl - they serve the same function >> as Machinist, but don''t (afaik) add methods to ActiveRecord::Base. > > Actually, I''ve taken a look at Factory Girl, but prefered Machinist, > which is awesome. I''ll take a look at Fixjour and Fixture > Replacement. Do they have a blueprint-like feature? > > I have no problem in creating methods in ActiveRecord::Base. I just > wanted to call something like: > > User.make_without_blueprint(:email => ''test at test.com'', :active => > ''false'')How about make_inactive and put it directly on User? Also, there may be some sort of named blueprint feature. I''m not in a position to look that up right now, but I think I remember that being supported. If not, we should make it so :)> > Thank you for your feedback, > > Rodrigo. > > __________________________________________________ > Fa?a liga??es para outros computadores com o novo Yahoo! Messenger http://br.beta.messenger.yahoo.c > om/ _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users
Em 28-10-2009 00:21, David Chelimsky escreveu:> >> ... >> Actually, I''ve taken a look at Factory Girl, but prefered Machinist, >> which is awesome. I''ll take a look at Fixjour and Fixture >> Replacement. Do they have a blueprint-like feature? >> >> I have no problem in creating methods in ActiveRecord::Base. I just >> wanted to call something like: >> >> User.make_without_blueprint(:email => ''test at test.com'', :active => >> ''false'') > > How about make_inactive and put it directly on User? > > Also, there may be some sort of named blueprint feature. I''m not in a > position to look that up right now, but I think I remember that being > supported. If not, we should make it so :)Thank you for making me going back to my first try. It is a long story: The first thing I tried out was: User.create(:active => false, :email => ''test at test.com'') At that time it didn''t work because the user was being persisted and the next time I was running the test it gived me an error because of duplicate e-mail. I associated that User.make would act diferently, turning on the rollback, but actually I figured out later that the problem was that I was calling it from before(:all). When I changed to before(:each) I had already created a named blueprint that reset the other fields generated by the default blueprint. After reading your message, I came back to my original try and guess what: It works! :) The problem was the before(:all) that I tried at the beggining... Thank you once more, Rodrigo. __________________________________________________ Fa?a liga??es para outros computadores com o novo Yahoo! Messenger http://br.beta.messenger.yahoo.com/