jabalsad
jabalsad

Reputation: 2421

Validate response from a yielded block

Assume I am testing the following class:

class Processor
  def initialize(tree)
    @tree = tree
  end

  def process(entity)
    @tree.each_branch do |branch|
      branch.inject({}) do |result, fruit|
        result[fruit.name] = fruit.type == entity.type
      end
    end
  end
end

I'd like to inject a stubbed tree, in my spec I would have:

describe Processor do
  let(:tree) { double("tree") }
  let(:apple) { Fruit.new("apple") }
  let(:processor) { Processor.new(tree) }

  let(:fruit1) { Fruit.new("orange") }
  let(:fruit2) { Fruit.new("apple") }

  it "should process a fruit"
    tree.stub(:each_branch).and_yield([fruit1, fruit2])
    Processor.process(apple)
  end
end

I would expect the following hash to be created in the block. How do I verify that it is created correctly and returned to the caller of the block?

{ "orange" => false, "apple" => true }

EDIT: I omitted details of the Fruit class, it should be irrelevant.

Upvotes: 1

Views: 41

Answers (1)

Jon Cairns
Jon Cairns

Reputation: 11951

If you're ever having to try and catch the result somewhere in the middle of a method that your testing, it's normally a good sign that you need to refactor.

Here's an example: add a method to the branch, then test the branch class (assuming it's a class that you're in control of).

class Branch
  def unique_fruits
    inject({}) do |result, fruit|
      result[fruit.name] = fruit.type == entity.type
    end
  end
end

class Processor
  # snip ...
  def process(entity)
    @tree.each_branch do |branch|
      branch.unique_fruits
    end
  end
end

That's easier to test, as inject returns the hash. You can write a unit test for the branch class and isolate that method. Then in the Processor#process method you replace the inject block with a call to branch.unique_fruits.

If you don't have control over branch, just extract the block to another method on the Processor class:

class Processor
  # snip...

  def process(entity)
    @tree.each_branch do |branch|
      unique_fruits_on_branch(branch)
    end
  end

  def unique_fruits_on_branch(branch)
    branch.inject({}) do |result, fruit|
      result[fruit.name] = fruit.type == entity.type
    end
  end
end

However, you can probably see that it doesn't look as nice - the Processor class is working at different levels of abstraction. But both of these are easier to unit test.

Upvotes: 1

Related Questions