How to mock an actual Object#method call using Mocha in Ruby? - ruby

Interacting directly with brains is not easy, so I have a little Gateway Pattern in use with some Dependency Inversion.
NumberCruncher is a wrapper for my Brain class.
class NumberCruncher
def initialize brain = Brain.new
#brain = brain
end
def times_one_hundred *numbers
numbers.map &#brain.method(:multiply_by_100)
end
end
I'm getting an error when testing though:
NameError: undefined method `multiply_by_100' for class `Mocha::Mock'
Here's the test
class NumberCruncherTest
def setup
#brain = mock
#cruncher = NumberCruncher.new #brain
end
def test_times_one_hundred
#brain.expects(:multiply_by_100).with(1).returns(100)
#brain.expects(:multiply_by_100).with(2).returns(200)
#brain.expects(:multiply_by_100).with(3).returns(300)
assert_equal [100, 200, 300], #cruncher.times_one_hundred(1,2,3)
end
end
I'm assuming it's because of the &#brain.method(:multiply_by_100) call and mocha works by using method_missing or something. The only solution seems to be to change the setup
class NumberCruncherTest
class FakeBrain
def multiply_by_100; end
end
def setup
#brain = FakeBrain.new
#cruncher = NumberCruncher.new #brain
end
# ...
end
However, I think this solution kind of sucks. It gets messy fast and it putting tons of Fake* classes all over my tests. Is there any better way to do this with mocha?

I think you can fix your problem by changing your method.
from
numbers.map &#brain.method(:multiply_by_100)
# which is equivalent to (just to understand the rest of my answer)
numbers.map {|number| #brain.method(:multiply_by_100).to_proc.call(number) }
to
numbers.map {|number| #brain.send(:multiply_by_100, number) }
This is actually better because there are some issues with your code. Transforming an object method into a proc (as you are doing), kinda freezes the state of your object into the proc and so any changes on instance variables will not take effect, and probably it's slower. send should work fine on your case, and works with any mocking framework.
Btw, my guess on why your test does not work it's because mocha does not stub proc methods, and for good, because if you transform a method into a proc, you are not testing a method call anymore but a proc call.
And because everyone loves benchmarks:
#o = Object.new
def with_method_to_proc
#o.method(:to_s).to_proc.call
end
def with_send
#o.send(:to_s)
end
def bench(n)
s=Time.new
n.times { yield }
e=Time.new
e-s
end
bench(100) { with_method_to_proc }
# => 0.000252
bench(100) { with_send }
# => 0.000106
bench(1000) { with_method_to_proc }
# => 0.004398
bench(1000) { with_send }
# => 0.001402
bench(1000000) { with_method_to_proc }
# => 2.222132
bench(1000000) { with_send }
# => 0.686984

Related

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.
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.

How to expect a method call on a newly created test double?

Say I have code like this:
class Car
def test_drive!; end
end
class AssemblyLine
def produce!
car = Car.new
car.test_drive!
end
end
Now, using RSpec I want to test/spec AssemblyLine without exercising Car as well. I hear we don't do dependency injection in Ruby, we stub new instead:
describe AssemblyLine
before do
Car.stub(:new).and_return(double('Car'))
end
describe '#produce'
it 'test-drives new cars' do
the_new_instance_of_car.should_receive(:test_drive) # ???
AssemblyLine.new.produce!
end
end
end
The problem, as you can see, is with the_new_instance_of_car. It doesn't exist yet before produce is called, and after produce returns it's too late to set any method call expectations on it.
I can think of a workaround involving a callback in the stubbed new method, but that's rather hideous. There must be a more elegant and idiomatic way to solve this seemingly common problem. Right...?
Update: here's how I solved it.
describe AssemblyLine
def stub_new_car(&block)
Car.stub(:new) do
car = double('Car')
block.call(car) if block
car
end
end
before { stub_new_car } # to make other tests use the stub as well
describe '#produce'
it 'test-drives new cars' do
stub_new_car { |car| car.should_receive(:test_drive) }
AssemblyLine.new.produce!
end
end
end
You can set an expectation on the test double:
describe AssemblyLine do
let(:car) { double('Car') }
before { Car.stub(:new) { car } }
describe "#produce" do
it "test-drives new cars" do
car.should_receive(:test_drive!)
AssemblyLine.new.produce!
end
end
end
You can also call any_instance on the class (as of RSpec 2.7, I think):
describe AssemblyLine do
describe "#produce" do
it "test-drives new cars" do
Car.any_instance.should_receive(:test_drive!)
AssemblyLine.new.produce!
end
end
end

Change the binding of a Proc in Ruby

I have this code:
l = lambda { a }
def some_function
a = 1
end
I just want to access a by the lambda and a special scope which has defined a already somewhere like inside some_function in the example, or just soon later in the same scope as:
l = lambda { a }
a = 1
l.call
Then I found when calling l, it is still using its own binding but not the new one where it was called.
And then I tried to use it as:
l.instance_eval do
a = 1
call
end
But this also failed, it is strange that I can't explain why.
I know the one of the solution is using eval, in which I could special a binding and executing some code in text, but I really do not want to use as so.
And, I know it is able to use a global variable or instance variable. However, actually my code is in a deeper embedded environment, so I don't want to break the completed parts if not quite necessary.
I have referred the Proc class in the documentation, and I found a function names binding that referred to the Proc's context. While the function only provided a way to access its binding but cannot change it, except using Binding#eval. It evaluate text also, which is exactly what I don't like to do.
Now the question is, do I have a better (or more elegant) way to implement this? Or using eval is already the regular manner?
Edit to reply to #Andrew:
Okay, this is a problem which I met when I'm writing a lexical parser, in which I defined a array with fixed-number of items, there including at least a Proc and a regular expression. My purpose is to matching the regular expressions and execute the Procs under my special scope, where the Proce will involved some local variables that should be defined later. And then I met the problem above.
Actually I suppose it is not same completely to that question, as mine is how to pass in binding to a Proc rather than how to pass it out.
#Niklas:
Got your answer, I think that is what exactly I want. It has solved my problem perfectly.
You can try the following hack:
class Proc
def call_with_vars(vars, *args)
Struct.new(*vars.keys).new(*vars.values).instance_exec(*args, &self)
end
end
To be used like this:
irb(main):001:0* lambda { foo }.call_with_vars(:foo => 3)
=> 3
irb(main):002:0> lambda { |a| foo + a }.call_with_vars({:foo => 3}, 1)
=> 4
This is not a very general solution, though. It would be better if we could give it Binding instance instead of a Hash and do the following:
l = lambda { |a| foo + a }
foo = 3
l.call_with_binding(binding, 1) # => 4
Using the following, more complex hack, this exact behaviour can be achieved:
class LookupStack
def initialize(bindings = [])
#bindings = bindings
end
def method_missing(m, *args)
#bindings.reverse_each do |bind|
begin
method = eval("method(%s)" % m.inspect, bind)
rescue NameError
else
return method.call(*args)
end
begin
value = eval(m.to_s, bind)
return value
rescue NameError
end
end
raise NoMethodError
end
def push_binding(bind)
#bindings.push bind
end
def push_instance(obj)
#bindings.push obj.instance_eval { binding }
end
def push_hash(vars)
push_instance Struct.new(*vars.keys).new(*vars.values)
end
def run_proc(p, *args)
instance_exec(*args, &p)
end
end
class Proc
def call_with_binding(bind, *args)
LookupStack.new([bind]).run_proc(self, *args)
end
end
Basically we define ourselves a manual name lookup stack and instance_exec our proc against it. This is a very flexible mechanism. It not only enables the implementation of call_with_binding, it can also be used to build up much more complex lookup chains:
l = lambda { |a| local + func(2) + some_method(1) + var + a }
local = 1
def func(x) x end
class Foo < Struct.new(:add)
def some_method(x) x + add end
end
stack = LookupStack.new
stack.push_binding(binding)
stack.push_instance(Foo.new(2))
stack.push_hash(:var => 4)
p stack.run_proc(l, 5)
This prints 15, as expected :)
UPDATE: Code is now also available at Github. I use this for one my projects too now.
class Proc
def call_with_obj(obj, *args)
m = nil
p = self
Object.class_eval do
define_method :a_temp_method_name, &p
m = instance_method :a_temp_method_name; remove_method :a_temp_method_name
end
m.bind(obj).call(*args)
end
end
And then use it as:
class Foo
def bar
"bar"
end
end
p = Proc.new { bar }
bar = "baz"
p.call_with_obj(self) # => baz
p.call_with_obj(Foo.new) # => bar
Perhaps you don't actually need to define a later, but instead only need to set it later.
Or (as below), perhaps you don't actually need a to be a local variable (which itself references an array). Instead, perhaps you can usefully employ a class variable, such as ##a. This works for me, by printing "1":
class SomeClass
def l
#l ||= lambda { puts ##a }
end
def some_function
##a = 1
l.call
end
end
SomeClass.new.some_function
a similar way:
class Context
attr_reader :_previous, :_arguments
def initialize(_previous, _arguments)
#_previous = _previous
#_arguments = _arguments
end
end
def _code_def(_previous, _arguments = [], &_block)
define_method("_code_#{_previous}") do |_method_previous, _method_arguments = []|
Context.new(_method_previous, _method_arguments).instance_eval(&_block)
end
end
_code_def('something') do
puts _previous
puts _arguments
end

Mocking a dynamically-generated class in ruby metaprogramming with rspec

I'm new to TDD and metaprogramming so bear with me!
I have a Reporter class (to wrap the Garb ruby gem) that will generate a new report class on-the-fly and assign it to a GoogleAnalyticsReport module when I hit method_missing. The main gist is as follows:
# Reporter.rb
def initialize(profile)
#profile = profile
end
def method_missing(method, *args)
method_name = method.to_s
super unless valid_method_name?(method_name)
class_name = build_class_name(method_name)
klass = existing_report_class(class_name) ||
build_new_report_class(method_name, class_name)
klass.results(#profile)
end
def build_new_report_class(method_name, class_name)
klass = GoogleAnalyticsReports.const_set(class_name, Class.new)
klass.extend Garb::Model
klass.metrics << metrics(method_name)
klass.dimensions << dimensions(method_name)
return klass
end
The type of 'profile' that the Reporter expects is a Garb::Management::Profile.
In order to test some of my private methods on this Reporter class (such as valid_method_name? or build_class_name), I believe I want to mock the profile with rspec as it's not a detail that I'm interested in.
However, the call to klass.results(#profile) - is executing and killing me, so I haven't stubbed the Garb::Model that I'm extending in my meta part.
Here's how I'm mocking and stubbing so far... the spec implementation is of course not important:
describe GoogleAnalyticsReports::Reporter do
before do
#mock_model = mock('Garb::Model')
#mock_model.stub(:results) # doesn't work!
#mock_profile = mock('Garb::Management::Profile')
#mock_profile.stub!(:session)
#reporter = GoogleAnalyticsReports::Reporter.new(#mock_profile)
end
describe 'valid_method_name' do
it 'should not allow bla' do
#reporter.valid_method_name?('bla').should be_false
end
end
end
Does anyone know how I can stub the call to the results method on my newly created class?
Any pointers will be greatly appreciated!
~ Stu
Instead of:
#mock_model = mock('Garb::Model')
#mock_model.stub(:results) # doesn't work!
I think you want to do:
Garb::Model.any_instance.stub(:results)
This will stub out any instance of Garb::Model to return results. You need to do this because you are not actually passing #mock_model into any class/method that will use it so you have to be a bit more general.

How do I call a method that is a hash value?

Previously, I asked about a clever way to execute a method on a given condition "Ruby a clever way to execute a function on a condition."
The solutions and response time was great, though, upon implementation, having a hash of lambdas gets ugly quite quickly. So I started experimenting.
The following code works:
def a()
puts "hello world"
end
some_hash = { 0 => a() }
some_hash[0]
But if I wrap this in a class it stops working:
class A
#a = { 0 => a()}
def a()
puts "hello world"
end
def b()
#a[0]
end
end
d = A.new()
d.b()
I can't see why it should stop working, can anyone suggest how to make it work?
that code doesn't work. it executes a at the time it is added to the hash, not when it is retrieved from the hash (try it in irb).
It doesn't work in the class because there is no a method defined on the class (you eventually define a method a on the instance.
Try actually using lambdas like
{0 => lambda { puts "hello world" }}
instead
First of all, you are not putting a lambda in the hash. You're putting the result of calling a() in the current context.
Given this information, consider what the code in your class means. The context of a class definition is the class. So you define an instance method called a, and assign a class instance variable to the a hash containing the result of calling a in the current context. The current context is the class A, and class A does not have a class method called a, so you're trying to put the result of a nonexistent method there. Then in the instance method b, you try to access an instance variable called #a -- but there isn't one. The #a defined in the class context belongs to the class itself, not any particular instance.
So first of all, if you want a lambda, you need to make a lambda. Second, you need to be clear about the difference between a class and an instance of that class.
If you want to make a list of method names to be called on certain conditions, you can do it like this:
class A
def self.conditions() { 0 => :a } end
def a
puts "Hello!"
end
def b(arg)
send self.class.conditions[arg]
end
end
This defines the conditions hash as a method of the class (making it easy to access), and the hash merely contains the name of the method to call rather than a lambda or anything like that. So when you call b(0), it sends itself the message contained in A.conditions[0], which is a.
If you really just want to pretty this sort of thing up,
why not wrap all your methods in a class like so:
# a container to store all your methods you want to use a hash to access
class MethodHash
alias [] send
def one
puts "I'm one"
end
def two
puts "I'm two"
end
end
x = MethodHash.new
x[:one] # prints "I'm one"
x.two # prints "I'm one"
or, to use your example:
# a general purpose object that transforms a hash into calls on methods of some given object
class DelegateHash
def initialize(target, method_hash)
#target = target
#method_hash = method_hash.dup
end
def [](k)
#target.send(#method_hash[k])
end
end
class A
def initialize
#a = DelegateHash.new(self, { 0 => :a })
end
def a()
puts "hello world"
end
def b()
#a[0]
end
end
x = A.new
x.a #=> prints "hello world"
x.b #=> prints "hello world"
One other basic error that you made is that you initialized #a outside of any instance method -
just bare inside of the definition of A. This is a big time no-no, because it just doesn't work.
Remember, in ruby, everything is an object, including classes, and the # prefix means the instance
variable of whatever object is currently self. Inside an instance method definitions, self is an instance
of the class. But outside of that, just inside the class definition, self is the class object - so you defined
an instance variable named #a for the class object A, which none of the instances of A can get to directly.
Ruby does have a reason for this behaviour (class instance variables can be really handy if you know what
you're doing), but this is a more advanced technique.
In short, only initialize instance variables in the initialize method.
table = {
:a => 'test',
:b => 12,
:c => lambda { "Hallo" },
:d => def print(); "Hallo in test"; end
}
puts table[:a]
puts table[:b]
puts table[:c].call
puts table[:d].send( :print )
Well, the first line in your class calls a method that doesn't exist yet. It won't even exist after the whole class is loaded though, since that would be a call to the class method and you've only defined instance methods.
Also keep in mind that {0 => a()} will call the method a(), not create a reference to the method a(). If you wanted to put a function in there that doesn't get evaluated until later, you'd have to use some kind of Lambda.
I am pretty new to using callbacks in Ruby and this is how I explained it to myself using an example:
require 'logger'
log = Logger.new('/var/tmp/log.out')
def callit(severity, msg, myproc)
myproc.call(sev, msg)
end
lookup_severity = {}
lookup_severity['info'] = Proc.new { |x| log.info(x) }
lookup_severity['debug'] = Proc.new { |x| log.debug(x) }
logit = Proc.new { |x,y| lookup_sev[x].call(y) }
callit('info', "check4", logit)
callit('debug', "check5", logit)
a = ->(string="No string passed") do
puts string
end
some_hash = { 0 => a }
some_hash[0].call("Hello World")
some_hash[0][]

Resources