On 12/20/06, jshen <jaydonnell at yahoo.com>
wrote:>
> This is part of a rails project. The following method is part of the Ams
> class (a rails model). I''m a bit unsure of the rspec/bdd way of
testing this
> method.
>
> def persist_as_domains
> @current_domains.each do |d|
> dom = Domain.new
> dom.domain = d
> dom.source_id = 1
> dom.at = Time.now
> dom.save
> end
> end
>
> The following is what came out when I tried to write my test. Notice that
> the only thing I''m testing here is that each method is called a
certain
> number of times. This doesn''t test that the proper values are
passed to the
> Domain model which is something I''d like to test, but I
don''t know how to do
> that since the methods are called in a loop with a different value each
> time. Am I even approaching this the right way?
>
> context "persisting as Domain" do
> setup do
> @ams = Ams.new
> @ams.get
> @ams.process
> puts Domain.class
> Domain.should_receive(:new).exactly(10).times
> Domain.should_receive(:domain).exactly(10).times
> Domain.should_receive(:source_id).exactly(10).times
> Domain.should_receive(:at).exactly(10).times
> Domain.should_receive(:save).exactly(10).times
> puts Domain.class
> end
>
> specify "should create new domain and save" do
> @ams.persist_as_domains
> end
> end
> --
I strive to write specs BEFORE code. That helps me to create better designs.
In this case, you can save yourself a lot of headache by using create
on your Domain and taking control of the number of domains in @ams
(I''m guessing at some internals here, so sorry if I don''t get
this
exactly right):
context "persisting as Domain with one domain" do
setup do
@ams = Ams.new
@ams.instance_eval {@current_domains = ["http://somewhere.com"]}
Domain.should_receive(:create).once.with("http://somewhere.com",1,Time.now)
end
specify "should create new domain and save" do
@ams.persist_as_domains
end
end
class Ams
def initialize
@current_domains = []
end
def persist_as_domains
@current_domains.each {|d| Domain.create(d, 1, Time.now) }
end
end
The Time.now thing will probably break here so you may want to create
a time source other than Time:
context "persisting as Domain with one domain" do
setup do
@ams = Ams.new
mock_time = mock("time")
mock_time.stub!(:now)and_return(Time.now)
@ams.instance_eval {@time_source = mock_time}
@ams.instance_eval {@current_domains = ["http://somewhere.com"]}
Domain.should_receive(:create).once.with("http://somewhere.com",1,mock_time.now)
end
specify "should create new domain and save" do
@ams.persist_as_domains
end
end
class Ams
def initialize
@current_domains = []
@time_source = Time
end
def persist_as_domains
@current_domains.each {|d| Domain.create(d, 1, Time.now) }
end
end
I recognize that using time_source seems somehow offensive, but
there''s a general truth that statics and singletons, etc, make testing
difficult. It is quite common among strong TDD/BDD''ers to do this sort
of thing, though the specific approach may vary (i.e. some may prefer
explicit dependency injection rather than sneaking in values through
instance_eval).
Hope this helps.
David
> View this message in context:
http://www.nabble.com/need-some-guidance-with-a-test-tf2863821.html#a8003040
> Sent from the rspec-users mailing list archive at Nabble.com.
>
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>