My Writer model class does not have 'posted_posts' or 'rejected_posts' attributes on it. However, with this SQL:
posts = self.posts.select("sum(case when state = 'posted' then 1 else 0 end) as posted_posts, sum(case when state = 'rejected' then 1 else 0 end) as rejected_posts")
I can access those 'properties' on the Writer instance. When I using RSpec though, I don't want to have to make this query, but I am unable to set those properties of the Writer instance because it thinks I am calling a method instead:
writer.rejected_posts = 8
The above line results in "undefined method 'rejected_posts'"
To 'mock' those properties, I did this:
describe "performance_score" do
it "should return a score based on the posted_posts and rejected_posts algorithm" do
class Writer
attr_accessor :posted_posts, :rejected_posts
end
writer = Factory(:writer)
writer.rejected_posts = 8
writer.posted_posts = 2
writer.performance_score.should == 80
end
end
My main question is how are these methods being added to the class. How does creating a new Writer class know to 'sync' up with my writer factory? I thought I was making a new Writer class for this test, but the strange thing is I still have access to other attributes from my writer factory. Hope this made sense, thanks.
Also, has anyone else done something similar in a test, is this the best way to handle this situation? It'd be nice if you tried to set a property that didn't exist that it would just create it, like it does in JavaScript.
The thing that is returned from your select query is probably not really a Writer
model. It is probably an ActiveRecord::Relation
. In order to provide the methods you have assigned values to in the SQL statement, it is probably implementing method_missing
and checks some kind of internal hash setup by AREL.
For mocking in tests, what you did will certainly work. Another option would be to use stub
.
it "should return a score based on the posted_posts and rejected_posts algorithm" do
writer = Factory(:writer)
writer.stub(:rejected_posts => 8)
writer.stub(:posted_posts => 2)
writer.performance_score.should == 80
end