How do I subclass mocks in Mocha? - ruby

I need to mock an object whose class is expected to have a few constants defined, e.g:
class Driver
DRIVER_NAME = "google"
end
I don't want to simply use instances of the class in my unit tests because of expensive initialization, plus it has a simple interface so it's optimal to mock. If I could simply subclass Mocha::Mock and add a few constants that would be perfect. I haven't found a way to instantiate those subclasses though. They require "mockery" as the initialize argument. I tried:
TestDriver.new(self.mock.instance_method_get(:#mockery))
Which quite funnily resulted in:
unexpected invocation: #<Mock:0x35c0690>.instance_method_get(:#mockery)
The source of Mocha is quite complex and entangled. I can't even find the point where mock is created for each Minitest::Test object.
So how do I subclass mocks in Mocha? Is there a straight forward way?
My backup solution is to simply use the three-line class shown above with driver.stubs(:name)... instead of using mocks, but that feels like the wrong way to solve the issue.

I just realized (by accident) that I can call expects on any object, not just mocks...
class TestDriverManager
def test_something
foo = TestDriver.new
foo.expects(:valid?).returns(true).once
# ...
end
class TestDriver
DRIVER_NAME = "test"
...
end
end
So there really is no need, at least not in my case, to subclass mock.

Related

Weird Ruby class initialization logic?

Some open source code I'm integrating in my application has some classes that include code to that effect:
class SomeClass < SomeParentClass
def self.new(options = {})
super().tap { |o|
# do something with `o` according to `options`
}
end
def initialize(options = {})
# initialize some data according to `options`
end
end
As far as I understand, both self.new and initialize do the same thing - the latter one "during construction" and the former one "after construction", and it looks to me like a horrible pattern to use - why split up the object initialization into two parts where one is obviously "The Wrong Think(tm)"?
Ideally, I'd like to see what is inside the super().tap { |o| block, because although this looks like bad practice, just maybe there is some interaction required before or after initialize is called.
Without context, it is possible that you are just looking at something that works but is not considered good practice in Ruby.
However, maybe the approach of separate self.new and initialize methods allows the framework designer to implement a subclass-able part of the framework and still ensure setup required for the framework is completed without slightly awkward documentation that requires a specific use of super(). It would be a slightly easier to document and cleaner-looking API if the end user gets functionality they expect with just the subclass class MyClass < FrameworkClass and without some additional note like:
When you implement the subclass initialize, remember to put super at the start, otherwise the magic won't work
. . . personally I'd find that design questionable, but I think there would at least be a clear motivation.
There might be deeper Ruby language reasons to have code run in a custom self.new block - for instance it may allow constructor to switch or alter the specific object (even returning an object of a different class) before returning it. However, I have very rarely seen such things done in practice, there is nearly always some other way of achieving the goals of such code without customising new.
Examples of custom/different Class.new methods raised in the comments:
Struct.new which can optionally take a class name and return objects of that dynamically created class.
In-table inheritance for ActiveRecord, which allows end user to load an object of unknown class from a table and receive the right object.
The latter one could possibly be avoided with a different ORM design for inheritance (although all such schemes have pros/cons).
The first one (Structs) is core to the language, so has to work like that now (although the designers could have chosen a different method name).
It's impossible to tell why that code is there without seeing the rest of the code.
However, there is something in your question I want to address:
As far as I understand, both self.new and initialize do the same thing - the latter one "during construction" and the former one "after construction"
They do not do the same thing.
Object construction in Ruby is performed in two steps: Class#allocate allocates a new empty object from the object space and sets its internal class pointer to self. Then, you initialize the empty object with some default values. Customarily, this initialization is performed by a method called initialize, but that is just a convention; the method can be called anything you like.
There is an additional helper method called Class#new which does nothing but perform the two steps in sequence, for the programmer's convenience:
class Class
def new(*args, &block)
obj = allocate
obj.send(:initialize, *args, &block)
obj
end
def allocate
obj = __MagicVM__.__allocate_an_empty_object_from_the_object_space__
obj.__set_internal_class_pointer__(self)
obj
end
end
class BasicObject
private def initialize(*) end
end
The constructor new has to be a class method since you start from where there is no instance; you can't be calling that method on a particular instance. On the other hand, an initialization routine initialize is better defined as an instance method because you want to do something specifically with a certain instance. Hence, Ruby is designed to internally call the instance method initialize on a new instance right after its creation by the class method new.

Creating facade idiomatically in Ruby

I'm trying to implement a Facade in idiomatic Ruby while coming from Java. I can see that Rails' ActiveRecord is fond of using class methods for things like find_by(criteria) and does not use Repository pattern for that task.
My Facade wraps a specific webservice with several methods. My original idea was to make it's API similar to ActiveRecord (learning by imitation):
class MyEntity
# ....
def get_name
#loaded_name + #loaded_surname
end
def delete
#entity_access_service.delete(#id)
end
def save
#entity_access_service.save(#id, #loaded_name , #loaded_surname)
end
def self.find(id)
data = #entity_access_service.get_data_for(id)
MyEntity.new(data) #Or whatever way to populate my entity
end
end
This, in theory, would work great:
e = MyEntity.find(10)
p e.get_name
e.delete
Or:
e = MyEntity.new(some stuff)
e.save
Question:
For save and delete instance methods to work, I need to somehow get an instance of EntityAccessService. This instance should be mockable to test it in isolated environment. What is the correct way to do it?
I'm expecting my tests to look as simple as possible and without some weird hacks, as what I'm trying to implement seems fairly trivial.
I have thought of several options to do that:
Having a class-level variable holding entity_access_service used by all of the entities created in application. In this case, where should I initialize this field? For example:
class MyEntity
##entity_access_service = nil
end
# Somewhere else (where?):
MyEntity.entity_access_service = MyEntityService.new(some_params_from_env)
This way, in my tests I would have to initialize/mock it at start.
Similar to 1 but initialize it in the class. This looks weird, especially if I know that my tests do not have required ENV params populated at all.
Have an extra constructor/attribute to set the entity_service. This won't work, as save would not have this field initialized.
Create a Repository class. This would work pretty ok, but seems to be not what Ruby people do.
Following ActiveRecord's example, you can create a method on your class itself, or on the base class from which your other classes are derived.
ActiveRecord provides a method ActiveRecord::Base.connection which returns the connection object which all models use to access the database. You can do something similar:
class MyEntity
....
def self.entity_access_service
# return your service object
end
def self.find(id)
MyEntity.entity_access_service.get_data_for(id)
MyEntity.new(data) # Or whatever way to populate my entity
end
def save()
MyEntity.entity_access_service.save(#id, #loadedName, #loadedSurname)
end
end
As far as initialization goes, you either have to have a initialization step in your app (and test suite) where service credentials are read from config files and passed into your MyEntity object, or your entity_access_service method can lazily create the object it returns on first access using a very common Ruby idiom:
def self.entity_access_service
#entity_access_service || = # build entity_access_service object
end
Note that, by wrapping your class-level instance variables in class-level accessor methods, you can avoid the use of ## which is a recommended best practice.

How can I mock super in ruby using rspec?

I am extending an existing library by creating a child class which extends to the library class.
In the child class, I was able to test most of functionality in initialize method, but was not able to mock super call. The child class looks like something like below.
class Child < SomeLibrary
def initialize(arg)
validate_arg(arg)
do_something
super(arg)
end
def validate_arg(arg)
# do the validation
end
def do_something
#setup = true
end
end
How can I write rspec test (with mocha) such that I can mock super call? Note that I am testing functionality of initialize method in the Child class. Do I have to create separate code path which does not call super when it is provided with extra argument?
You can't mock super, and you shouldn't. When you mock something, you are verifying that a particular message is received, and super is not a message -- it's a keyword.
Instead, figure out what behavior of this class will change if the super call is missing, and write an example that exercises and verifies that behavior.
As #myron suggested you probably want to test the behavior happening in super.
But if you really want to do this, you could do:
expect_any_instance_of(A).to receive(:instance_method).and_call_original
Assuming
class B < A
def instance_method
super
end
end
class A
def instance_method
#
end
end
Disclaimer expect_any_instance_of are a mark of weak test (see):
This feature is sometimes useful when working with legacy code, though
in general we discourage its use for a number of reasons:
The rspec-mocks API is designed for individual object instances, but
this feature operates on entire classes of objects. As a result there
are some semantically confusing edge cases. For example, in
expect_any_instance_of(Widget).to receive(:name).twice it isn't clear
whether a specific instance is expected to receive name twice, or if
two receives total are expected. (It's the former.)
Using this feature is often a design smell. It may be that your test is trying to do too much or that the object under test is too
complex.
It is the most complicated feature of rspec-mocks, and has historically received the most bug reports. (None of the core team
actively use it, which doesn't help.)
A good way to test this is to set an expectation of some action taken by the superclass - example :
class Some::Thing < Some
def instance_method
super
end
end
and the super class:
class Some
def instance_method
another_method
end
def self.another_method # not private!
'does a thing'
end
end
now test :
describe '#instance_method' do
it 'appropriately triggers the super class method' do
sawm = Some::Thing.new
expect(sawm).to receive(:another_method)
sawm.instance_method
end
end
All This Determines Is That Super Was Called On the Superclass
This pattern's usefulness is dependent on how you structure your tests/what expectations you have of the child/derivative class' mutation by way of the super method being applied.
Also - pay close attention to class and instance methods, you will need to adjust allows and expects accordingly
YMMV
A bit late to this party, but what you can also do is forego using the super keyword and instead do
class Parent
def m(*args)
end
end
class Child < Parent
alias super_m m
def m(*args)
super_m(*args)
end
end
That way your super method is accessible like any other method and can e.g. be stubbed like any other method. The main downside is that you have to explicitly pass arguments to the call to the super method.

What is double method in rspec for?

It is stated in rspec doc that I should use double method in order to create test double.
But I can see that it works perfectly ok even if I don't use double. Is there anything wrong with not using double? Also if I'm not using double how MyClass gets stub and other rspec methods? Are they available for all objects when running in rspec?
require 'spec_helper'
class MyClass
def self.run
new.execute
end
def execute
'foo'
end
end
describe MyClass do
it 'should stub instance method' do
obj = MyClass.new
obj.stub(:execute).and_return('bar')
obj.execute.should == 'bar'
end
it 'should stub class method' do
MyClass.stub(:run).and_return('baz')
MyClass.run.should == 'baz'
end
end
Edit: I just reread your question and realized I didn't quite answer it. Leaving my original answer because it's related, but here's your specific answer:
The reason you don't need a double is because you're stubbing class methods, rather than instance methods. double is only useful for dealing with instances of the class, not the class itself.
Old answer that explains double some more:
You should always use real classes instead of test doubles when you can. This will exercise more of your code and make your tests more comprehensive. Test doubles are used in situations where you can't or shouldn't use a real object. For example, if a class can't be instantiated without hitting an external resource (like a network or a database), or has a large number of dependencies, and you're just testing something that uses it, you might want to create a double and stub some methods on the double.
Here's a more specific example: let's say you are testing MyClass, but in order to instantiate MyClass, you need to pass in a FooLogger:
mylogger = FooLogger.new
myclass = MyClass.new logger: mylogger
If FooLogger.new opens a syslog socket and starts spamming it right away, every time you run your tests, you'll be logging. If you don't want to spam your logs during this test, you can instead create a double for FooLogger and stub out a method on it:
mylogger = double(FooLogger)
mylogger.stub(:log)
myclass = MyClass.new logger: mylogger
Because most well-designed classes can be instantiated without any side-effects, you can usually just use the real object instead of a double, and stub methods on that instead. There are other scenarios where classes have many dependencies that make them difficult to instantiate, and doubles are a way to get past the cruft and test the thing you really care about.
In my experience, needing to use a double is a code smell, but we often have to use classes that we can't easily change (e.g. from a gem), so it's a tool you might need from time to time.
With RSpec Mocks 3.0 the behaviour of doubles has changed. You now may verify doubles, which means "RSpec will check that the methods
being stubbed are actually present on the underlying object if it is available", but "no checking will happen if the underlying object or class is not defined".
Verifying doubles requests you to be specific about the double type (instance, class, object, dynamic class, partial). Here is an example from the RSpec Relish for an instance double:
RSpec.describe User, '#suspend!' do
it 'notifies the console' do
notifier = instance_double("ConsoleNotifier")
expect(notifier).to receive(:notify).with("suspended as")
user = User.new(notifier)
user.suspend!
end
end

Static block in Ruby

I have been a Java programmer for a while and I am trying to switch to ruby for a while. I was just trying to develop a small test program in ruby and my intention is something like following.
I want to create a simple linked list type of an object in ruby; where an instance variable in class points to another instance of same type.
I want to populate and link all nodes; before the constructor is called and only once. Something that we'd usually do in Java Static block.
Initialize method is a constructor signature in ruby. Are there any rules around them? Like in Java you cannot call another constructor from a constructor if its not the first line (or after calling the class code?)
Thanks for the help.
-Priyank
I want to create a simple linked list type of an object in ruby; where an instance variable in class points to another instance of same type.
Just a quick note: the word type is a very dangerous word in Ruby, especially if you come from Java. Due to an historic accident, the word is used both in dynamic typing and in static typing to mean two only superficially related, but very different things.
In dynamic typing, a type is a label that gets attached to a value (not a reference).
Also, in Ruby the concept of type is much broader than in Java. In Java programmer's minds, "type" means the same thing as "class" (although that's not true, since Interfaces and primitives are also types). In Ruby, "type" means "what can I do with it".
Example: in Java, when I say something is of type String, I mean it is a direct instance of the String class. In Ruby, when I say something is of type String, I mean it is either
a direct instance of the String class or
an instance of a subclass of the String class or
an object which responds to the #to_str method or
an object which behaves indistinguishably from a String.
I want to populate and link all nodes; before the constructor is called and only once. Something that we'd usually do in Java Static block.
In Ruby, everything is executable. In particular, there is no such thing as a "class declaration": a class body is just exectuable code, just like any other. If you have a list of method definitions in your class body, those are not declarations that are read by the compiler and then turned into a class object. Those are expressions that get executed by the evaluator one by one.
So, you can put any code you like into a class body, and that code will be evaluated when the class is created. Within the context of a class body, self is bound to the class (remember, classes are just objects like any other).
Initialize method is a constructor signature in ruby. Are there any rules around them? Like in Java you cannot call another constructor from a constructor if its not the first line (or after calling the class code?)
Ruby doesn't have constructors. Constructors are just factory methods (with stupid restrictions); there is no reason to have them in a well-designed language, if you can just use a (more powerful) factory method instead.
Object construction in Ruby works like this: object construction is split into two phases, allocation and initialization. Allocation is done by a public class method called allocate, which is defined as an instance method of class Class and is generally never overriden. It just allocates the memory space for the object and sets up a few pointers, however, the object is not really usable at this point.
That's where the initializer comes in: it is an instance method called initialize, which sets up the object's internal state and brings it into a consistent, fully defined state which can be used by other objects.
So, in order to fully create a new object, what you need to do is this:
x = X.allocate
x.initialize
[Note: Objective-C programmers may recognize this.]
However, because it is too easy to forget to call initialize and as a general rule an object should be fully valid after construction, there is a convenience factory method called Class#new, which does all that work for you and looks something like this:
class Class
def new(*args, &block)
obj = alloc
obj.initialize(*args, &block)
return obj
end
end
[Note: actually, initialize is private, so reflection has to be used to circumvent the access restrictions like this: obj.send(:initialize, *args, &block)]
That, by the way, is the reason why to construct an object you call a public class method Foo.new but you implement a private instance method Foo#initialize, which seems to trip up a lot of newcomers.
To answer your question: since an initializer method is just a method like any other, there are absolutely no restrictions as to what you can do whithin an initializer, in particular you can call super whenever, wherever, however and how often you want.
BTW: since initialize and new are just normal methods, there is no reason why they need to be called initialize and new. That's only a convention, although a pretty strong one, since it is embodied in the core library. In your case, you want to write a collection class, and it is quite customary for a collection class to offer an alternative factory method called [], so that I can call List[1, 2, 3] instead of List.new(1, 2, 3).
Just as a side note: one obvious advantage of using normal methods for object construction is that you can construct instances of anonymous classes. This is not possible in Java, for absolutely no sensible reason whatsoever. The only reason why it doesn't work is that the constructor has the same name as the class, and anonymous classes don't have a name, ergo there cannot be a constructor.
Although I am not quite sure why you would need to run anything before object creation. Unless I am missing something, shouldn't a list basically be
class List
def initialize(head=nil, *tail)
#head = head
#tail = List.new(*tail) unless tail.empty?
end
end
for a Lisp-style cons-list or
class List
def initialize(*elems)
elems.map! {|el| Element.new(el)}
elems.zip(elems.drop(1)) {|prv, nxt| prv.instance_variable_set(:#next, nxt)}
#head = elems.first
end
class Element
def initialize(this)
#this = this
end
end
end
for a simple linked list?
You can simply initialize your class variables in the class body, outside of any method declaration. It will behave like a static initializer in Java:
class Klass
##foo = "bar"
def sayFoo
puts ##foo
end
def self.sayFoo
puts ##foo
end
end
The class field ##foo is here initialized to "bar".
In ruby object creation works like this
class Class
def new(*args)
obj= self.allocate # get some memory
obj.send(:initialize) # call the private method initialize
end
end
Object#initialize is just an ordinary private method.
If you wan't something to happen before Object#initialize you have to write your own Class#new. But I see no reason why you would want to do that.
This is basically the same answer paradigmatic gave back in '09.
Here I want to illustrate that the "static initializer" can call other code. I'm simulating a scenario of loading a special user once, upon class initialization.
class Foo
def user
"Thomas"
end
end
class Bar
##my_user = Foo.new.user
def my_statically_defined_user
##my_user
end
end
b = Bar.new
puts b.my_statically_defined_user # ==> Thomas

Resources