Hi all I''m trying to write good unit tests. Here''s part of my blog_test.rb: --- blog_test.rb: require File.dirname(__FILE__) + ''/../test_helper'' class BlogTest < Test::Unit::TestCase fixtures :blogs, :comments def setup @valid_blog = Blog.new(valid_blog_attributes) end def test_should_be_able_to_have_many_comments @valid_blog.comments = {} assert_valid @valid_blog comments.each do |comment| @valid_blog.comments << comment assert_not_nil @valid_blog.comments assert_valid @valid_blog end end end --- comments.yml: first_comment: id: 1 subject: "Dies ist der erste Kommentar" body: "Dies ist der Inhalt des ersten Kommentars" second_comment: id: 2 subject: "Dies ist der zweite Kommentar" body: "Dies ist der Inhalt des zweiten Kommentars" The Comment model is :polymorphic => true, :as => :commentable. As we can see there are two comments available in the fixtures, but in when running the test_should_be_able_to_have_many_comments test, there are none! puts comments.size returns 0 all the time! Why aren''t they available? Thanks a lot for help. Josh -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
It seems that the fixtures are not correct (not complete). When I specify the commentable_type and _id, it works: commentable_type: "Blog" commentable_id: 1 Why is that? I''d like to put the fixtures as loose as possible into the database and then hardwire them to the needed other objects in each test, so for the blog_test.rb I wanted to do: def setup @valid_blog = Blog.new(valid_blog_attributes) @valid_blog.comments << comments end ...and I hoped that this would automatically set the commentable_type and _id to the needed values then. But this doesn''t seem so. So I guess I have to hardwire the stuff all in the fixtures... Or are there other, better ways to achieve better dynamics? -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Why not test by creating comments - bypass the comments fixtures all together? def test_should_be_able_to_have_many_comments blog = blog.create!(valid_blog_attributes) assert_difference "blog.comments" do blog.comments.create!(valid_comment_attributes) end end what version of rails are you using? On Apr 16, 10:46 am, Joshua Muheim <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> It seems that the fixtures are not correct (not complete). When I > specify the commentable_type and _id, it works: > > commentable_type: "Blog" > commentable_id: 1 > > Why is that? I''d like to put the fixtures as loose as possible into the > database and then hardwire them to the needed other objects in each > test, so for the blog_test.rb I wanted to do: > > def setup > @valid_blog = Blog.new(valid_blog_attributes) > @valid_blog.comments << comments > end > > ...and I hoped that this would automatically set the commentable_type > and _id to the needed values then. > > But this doesn''t seem so. So I guess I have to hardwire the stuff all in > the fixtures... Or are there other, better ways to achieve better > dynamics? > -- > Posted viahttp://www.ruby-forum.com/.--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Gavin wrote:> Why not test by creating comments - bypass the comments fixtures all > together? > > def test_should_be_able_to_have_many_comments > blog = blog.create!(valid_blog_attributes) > assert_difference "blog.comments" do > blog.comments.create!(valid_comment_attributes) > end > end > > what version of rails are you using? > > On Apr 16, 10:46�am, Joshua Muheim <rails-mailing-l...@andreas-s.net>Thanks, but I''m doing it now the hardwired way. :-) -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Joshua Muheim wrote:> I''m trying to write good unit tests. Here''s part of my blog_test.rb: > > --- blog_test.rb: > > require File.dirname(__FILE__) + ''/../test_helper'' > > class BlogTest < Test::Unit::TestCase > fixtures :blogs, > :comments > > def setup > @valid_blog = Blog.new(valid_blog_attributes)Don''t construct a blog - fetch one from the fixtures: @valid_blog = blogs(:valid_blog)> end > > def test_should_be_able_to_have_many_comments > @valid_blog.comments = {} > assert_valid @valid_blogThe assertion that the blog is valid should be in the setup or another test. Each test case should only speak to one activity.> comments.each do |comment|Where does comments come from? you are probably picking up comments(), which is the fixture loader. It returns an array unless you pass one comment, so you are now slipping off that array. Try this: comments(:first_comment, :second_comment).each do |comment|> @valid_blog.comments << comment > assert_not_nil @valid_blog.commentsAs you get better at testing, you will get bored with testing that ActiveRecord behaves as advertised, and you will test your actual logic. To set a good example here, don''t test against nil, because if comments were an empty array, then assert_not_nil [] would pass. Instead, test that the comment went in: assert{ @valid_blog.comments.last == comment } That illustrates two things. It shows my assert{ 2.0 }, which turns any expression into a generic assertion, and it shows AR evaluates == as true if two records have the same ID. assert{ @valid_blog.valid? }> end > end > end > > --- comments.yml: > > first_comment: > id: 1 > subject: "Dies ist der erste Kommentar" > body: "Dies ist der Inhalt des ersten Kommentars"If you use Rails >2, don''t use the id: 1. Let the fixturizer build the number for you. This makes coding much simpler. Next, don''t call it first_comment. Name it after the theme of your comment. -- Phlip --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Thanks for your useful hints, Philip. -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Apr 16, 9:37 am, Phlip <phlip2...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Joshua Muheim wrote:[...]> > def setup > > @valid_blog = Blog.new(valid_blog_attributes) > > Don''t construct a blog - fetch one from the fixtures: > > @valid_blog = blogs(:valid_blog)Why? In my experience, fixtures make tests brittle and hard to understand, so I''ve stopped using them entirely. What''s the advantage here? [...]> As you get better at testing, you will get bored with testing that ActiveRecord > behaves as advertised, and you will test your actual logic.Yeah. ActiveRecord has already been well tested. Focus on the code you wrote. (I know, that''s a tough concept to internalize -- I certainly don''t always manage...)> > To set a good example here, don''t test against nil, because if comments were an > empty array, then assert_not_nil [] would pass. > > Instead, test that the comment went in: > > assert{ @valid_blog.comments.last == comment } > > That illustrates two things. It shows my assert{ 2.0 }, which turns any > expression into a generic assertion,[...] Cool! Sexy RSpecish syntax for the unsexy Test::Unit! I''ll have to try it out! :P (Seriously, I think assert2 looks great, and I''m looking forward to trying it.) Best, -- Marnen Laibow-Koser http://www.marnen.org marnen-sbuyVjPbboAdnm+yROfE0A@public.gmane.org --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Marnen Laibow-Koser wrote:>>> def setup >>> @valid_blog = Blog.new(valid_blog_attributes) >> Don''t construct a blog - fetch one from the fixtures: >> >> @valid_blog = blogs(:valid_blog) > > Why? In my experience, fixtures make tests brittle and hard to > understand, so I''ve stopped using them entirely. What''s the advantage > here?(Let''s hope you have not replaced them all with totally empty mocks!) The advice for newbs, and possibly also for the original poster, is to use fixtures the way the tutorials specify. This gets them out of the starting gate. The advice, as a project grows, is to use some form of "scenarios", which are kits of fixtures tuned to specific situations. Example: new_customer, paid_up_customer, delinquent_customer, etc. If you don''t use raw fixtures, you should find yourself implementing a scenario system directly into your setup blocks. From there, you should re-use their support methods into some scenario library. Finally, I suspect the most advanced advice possible is to always write assertions that gracefully adapt to your data records, whether they be classic range-free fixtures, or isolated scenarios. Don''t do this: records = get_fithy_records() assert{ records.length == 17 } That breaks when you add a new filthy record, for whatever reason! Instead, do this: assert{ records.map(:status).uniq == [''filthy''] } This link emblogs the ideal of writing flexible tests, even when your code happens to implement something complex, such as a Minimum Spanning Tree: http://broadcast.oreilly.com/2009/02/merb-mind-maps.html>> As you get better at testing, you will get bored with testing that ActiveRecord >> behaves as advertised, and you will test your actual logic. > > Yeah. ActiveRecord has already been well tested. Focus on the code > you wrote. > > (I know, that''s a tough concept to internalize -- I certainly don''t > always manage...)When you are getting started with a new library, writing unit tests directly on the library is a best practice. So, you should indeed precede "Foo.has_many :bars" with a test that a foo object has a .bars collection full of bars. -- Phlip http://flea.sourceforge.net/resume.html --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---