[rspec-users] need some guidance with a test

David Chelimsky dchelimsky at gmail.com
Thu Dec 21 08:26:06 EST 2006


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
>


More information about the rspec-users mailing list