Is it good practice to write tests for private methods?
Consider the following simple example:
class Group
has_many :members
private
def release_members
members.each { |member| member.update_attributes group_id: nil }
end
end
Would it be good practice to write a test for the release_members method in RSpec? I believe you'd have to write the test calling the method with send ie. group.send(:release_members) which is sometimes frowned upon.
You shouldn't test private methods as they belong to the internal mechanism of the class. The purpose of Unit Tests is to check that your class behaves as expected when interacting with through its interface, i.e. its public methods.
If at a certain point you're not comfortable with long private methods, it's probably because you have here the opportunity to pull that logic outside of the class and build another module or class. Then, you can unit test it, again only its interface, i.e. its public methods.
In some rare cases, it is necessary to test the private methods because the whole internal logic is very complex and you'd like to split the problem. But in 99.9%, testing private methods is a bad idea.
You can find an in-depth discussion of that very subject in these slides from a Sandi Metz talk.
https://speakerdeck.com/skmetz/magic-tricks-of-testing-railsconf
She says that you may test-drive your private methods if you like, but that the only test that you should worry about are the ones testing the public interface. Otherwise you may be coupling too tightly to implementation.
I think the point by toch, on splitting out service and value object and putting those under tests is also a good one if you are getting nervous about complex private methods that aren't tested.
Related
Is it considered a good design to allow a private method in class A in ruby to call a public method in class B,
I guess a better approach would be to call another public method in class A which would call the public method in class B.
Consider a situation where a user needs to act (private method) on a resource but can't do so without examining some constraint (through a public method) of the resource.
I don't know what exact function you want, but it's no problem to allow a private method in class A in ruby to call a public method in class B like the code :
class A
private
def test_a
B.new.test_b
end
end
class B
def test_b
puts 'test_b'
end
end
A.new.send(:test_a) #=>test_b
Is it considered a good design to allow a private method in class A in
ruby to call a public method in class B
It doesn't matter whether you're calling the external class from a public or private method, as private methods are an implementation detail. What matters is whether it makes sense for the given class to know about that external classes' method.
Consider a situation where a user needs to act (private method) on a resource but can't do so without examining some constraint (through a public method) of the resource.
Taking into account your comment:
if the user wants to enter the house he needs to check if the house is safe
One possible implementation would be:
class User
def enter(house)
if house.safe?
house.users << user
end
end
end
This requires the User class to know a few things about the House class:
it implements a safety validation via #safe?
it stores entered users in a users array
This means User knows quite a bit about House. If House changes the implementation of the above two items, User needs to change too.
An alternate design would be to invert the owner of the functionality:
def House
def entry_for(user)
if safe?
users << user
end
end
end
Now, the coupling between these two classes has been reduced. As the owner of the safe? constraint, House controls whether users are allowed in while User remains blissfully ignorant of the implementation of House.
Depending on the domain in question, the assertion of safety might belong to a class other than House or User, eg. Guard. In this case, you might end up with something like:
class Guard
def facilitate_entry(user, house)
house.enter_by(user) if safe?(house)
end
private
def safe?(house)
end
end
I dont think that would be a good approach, to create a public methods to access other class's public methods. You would get overwhelmed with too many public methods in your class.
As Ruby is pure object oriented and everything is object there. If you go with that approach in mind, you will ended up with unnecessary methods. Even if you are doing simple stuff in your private method. Let say you are trying to iterating an array with each method. Would you consider creating a public methods to first to access public method each of class Array ? Answer is simply no.
Also ruby is an expressive and productive language. You could do more is less code in ruby.
How does one mock a utility method that is located in a file referenced by
require 'myfile.rb'
The contents of the file are like so.
public
def my_method_name(arg1, arg2, arg3)
{
....
}
At the moment, I have something like:
double("mydouble", "my_method_name" => somehash)
I then unit test the class I am testing, which calls this method, but this does not seem to be mocking the method at all.
All help is appreciated
Basically, the method I want to mock does some network query. I want to just say: Anytime this method is called, return this hash. This method is not part of a class (or so I believe).
In Ruby all methods are associated to something (module or class). Methods that you define at the top level actually become private methods of Kernel.
x = double("mydouble", "my_method_name" => somehash)
Doesn't stub the method my_method_name. It creates a double (separate object). If you invoke #my_method_name on it, it will respond with somehash:
x.my_method_name # => somehash
Find the object the method is being invoked on. If it's easily replaced and doesn't have that much more functions, you can pass this double instead on it's place. If that is not the case, you can stub the method on that object by doing:
said_object.stub(my_method_name: somehash)
If you want to stub it for all instances of a class, you could do:
TheObjectsClass.any_instance.stub(my_method_name: somehash)
Disclaimer: The topic is a bit more complex and subject to debate. Don't consider this as a good testing practice, it just aims to help you understand how to use rspec.
You said this is related to networking. You can consider using VCR to simulate actual requests.
Since the class you are testing is the one on which this method is called, you should be stubbing the method on the same class
allow(<your_class_instance>).to receive(:my_method_name).and_return(<>)
I am assuming this method is an instance method. If its a class method, you will have to stub it at the class level
I am trying to define methods that are private most of the time, but not always. For example:
class Service
def initialize(repo)
#repo = repo
end
private def repo
#repo
end
def all
repo.all
end
end
My class Service will implement features around a repository object. I want to completely hide away the repo object to prevent its leakage to my production code.
However when debugging or testing I want to be lazy and call service.repo directly instead using service.send :repo.
I thought about loading a class extension or dirty ENV var check for my tests and console, however that prevents my tests from breaking if code inside ./lib/* makes bad use of private methods during a test run.
Now I am exploring with refinements, but that requires too much boilerplate and I want to do some decorator like this:
+LibPrivate
def repo
#repo
end
That is a Python like decorator, but I believe since Ruby 2.1 it might be possible to define custom modifiers beyond private/public without that gem
Simply change the visibility of the method in your test helper or in your test file.
Service.class_eval do
public :repo
end
Just keep in mind that private method are in theory implementation details. You should not test private methods. In general, you test the behavior of the first public method that relies on the private.
If you feel that you need, then it may be the case where the method should not be private.
This rule doesn't have to be applied blindly, but it's good to keep it in mind.
I have a typical OO pattern: one base abstract class (that defines abstract methods) and several classes that implement these abstract methods in class-specific way.
I'm used to write documentation only once in abstract methods and then it automatically propagates to several concrete classes (at least it works the following way in Javadoc, in Scaladoc, in Doxygen), i.e. I don't need to repeat the same description in all concrete classes.
However, I couldn't find how to do such propagation in YARD. I've tried, for example:
# Some description of abstract class.
# #abstract
class AbstractClass
# Some method description.
# #return [Symbol] some return description
# #abstract
def do_something
raise AbstractMethodException.new
end
end
class ConcreteClass < AbstractClass
def do_something
puts "Real implementation here"
return :foo
end
end
What I get:
Code works as expected - i.e. throws AbstractMethodException is called in abstract class, does the job in concrete class
In YARD, AbstractClass is clearly defined as abstract, ConcreteClass is normal
Method description and return type is good in AbstractClass
Method is said to throw AbstractMethodException in AbstractClass
Method has no description at all and generic Object return type in ConcreteClass, there's not a single notice of that an abstract method exists in base class.
What I expect to get:
Method's description and return type are inherited (i.e. copied) to ConcreteClass from info at AbstractClass
Ideally, this method is specified in "inherited" or "implemented" section of ConcreteClass description, with some reference link from ConcreteClass#do_something to AbstractMethod#do_something.
Is it possible to do so?
I think the issue boils down to what you're trying to do. It looks like you're trying to implement an Interface in Ruby, which makes sense if you're coming from Java or .NET, but isn't really how Ruby developers tend to work.
Here is some info about how the typical thought on Interfaces in Ruby: What is java interface equivalent in Ruby?
That said, I understand what you're trying to do. If you don't want your AbstractClass to be implemented directly, but you want to define methods that can be used in a class that behaves like the AbstractClass stipulates (as in Design by Contract), then you probably want to use a Module. Modules work very well for keeping your code DRY, but they don't quite solve your problem related to documenting overridden methods. So, at this point I think you can reconsider how you approach documentation, or at least approach it in a more Ruby-ish way.
Inheritance in Ruby is really (generally speaking from my own experience) only used for a few reasons:
Reusable code and attributes
Default behaviors
Specialization
There are obviously other edge cases, but honestly this is what inheritance tends to be used for in Ruby. That doesn't mean what you're doing won't work or violates some rule, it just isn't typical in Ruby (or most dynamically typed languages). This atypical behavior is probably why YARD (and other Ruby doc generators) doesn't do what you expect. That said, creating an abstract class that only defines the methods that must exist in a subclass really gains you very little from a code perspective. Methods not defined will result in a NoMethodError exception being thrown anyway, and you could programmatically check if an object will respond to a method call (or any message for that matter) from whatever calls the method, using #respond_to?(:some_method) (or other reflective tools for getting meta stuff). It all comes back Ruby's use of Duck Typing.
For pure documentation, why document a method that you don't actually use? You shouldn't really care about the class of the object being sent or received from calling a method, just what those objects respond to. So don't bother creating your AbstractClass in the first place if it adds no real value here. If it contains methods you actually will call directly without overriding, then create a Module, document them there, and run $ yardoc --embed-mixins to include methods (and their descriptions) defined in mixed-in Modules. Otherwise, document methods where you actually implement them, as each implementation should be different (otherwise why re-implement it).
Here is how I would something similar to what you're doing:
# An awesome Module chock-full of reusable code
module Stuff
# A powerful method for doing things with stuff, mostly turning stuff into a Symbol
def do_stuff(thing)
if thing.kind_of?(String)
return thing.to_sym
else
return thing.to_s.to_sym
end
end
end
# Some description of the class
class ConcreteClass
include Stuff
# real (and only implementation)
def do_something
puts "Real implementation here"
return :foo
end
end
an_instance = ConcreteClass.new
an_instance.do_somthing # => :foo
# > Real implementation here
an_instance.do_stuff("bar") # => :bar
Running YARD (with --embed-mixins) will include the methods mixed-in from the Stuff module (along with their descriptions) and you now know that any object including the Stuff module will have the method you expect.
You may also want to look at Ruby Contracts, as it may be closer to what you're looking for to absolutely force methods to accept and return only the types of objects you want, but I'm not sure how that will play with YARD.
Not ideal, but you can still use the (see ParentClass#method) construct (documented here). Not ideal because you have to type this manually for every overriding method.
That being said, I'm no Yard specialist but given its especially customizable architecture, I'd be surprised that there would be no easy way to implement what you need just by extending Yard, somewhere in the Templates department I guess.
I have a two part question:
Part 1
I have a module that has a public class method which depends on a few private helper methods in the module. What is the best way to test these private helper methods? They contain complex logic that needs to be tested, but they should not be exposed to be called as they alone provide nothing useful.
I read on this stackoverflow post that the convention is to do:
module GTranslate
class Translator
def perform( text ); 'hola munda'; end
end
def self.translate( text )
t = Translator.new
t.perform( text )
end
end
and then write tests on the public methods of class GTranslate::Translator. However, I do not want this class to be able to instantiate or have the methods on them called.
Part 2
Seeing that the public method on a module is defined as self.someMethodName, does this mean the helper methods have to be defined as self.helperName?
There will be no instance of a module (if you can even create instances of modules (I'm new to Ruby)) so I can't use the send method defined on an instance to invoke the method from my tests?
Any ideas?
There is some bit of debate about testing private methods as you will see in other answers. Before you test them you should consider whether it is the best choice. David Brady has a great podcall with Robert C. (Uncle Bob) Martin where they discuss this issue and some of the possible solutions including testing through the public interface, and refactoring into a separate class.
That being said, this is Ruby. If you want to test private methods use instance_eval (or class_eval for class methods) to run your test in the context of the module.
edit: After some quick IRB work modules take a little more work
Given:
module Foo
class << self
private
def bar
...
end
end
end
To test Foo.bar put in your test file:
Module Foo
class << self
puiblic :bar
end
end
For the duration of your tests bar will be public and visible.
end edit
See also:
Yes You Should Test Private Methods (Sometimes)
Test Everything, But Not Private Methods
MORE Testing Private Method
I would say you have three options.
Find a way to test the functionality using the class's public methods. All the class functionality should generally be exposed by its public methods. If you can't test a class just by using its public methods, this may indicate a deeper problem with the design.
If option 1 doesn't work (and indeed sometimes it doesn't), refactor the private functionality out to a separate class, in which these methods are public. This seems to be what you're suggesting, and I don't see a problem with that. Testing is an integral part of the system you're building and should be treated as such. Making functionality public "just for testing" is completely valid in my opinion.
Make the functions public and test them. This is technically easiest but is less clean than option 2.
There are two cases:
The private method gets called by a public method, or by a private method that gets called by a public method, or by a private method that gets called by a private method that gets called by a public method, or … (you get the idea). In that case, you don't need to test the private method, because it is already tested through the public method.
The private method never gets called by a public method. In that case, you don't need to test it either, you can simply delete it because it never gets called.
So, in both cases you simply don't need to test it in the first place.
(Note that it's a little bit more complicated than that, since the private method might be called via reflection or other means. But the gist is: either someone somewhere calls the private method, in which case it is tested through that someone, or noone calls the private method, in which case it is dead code.)
If I may make a small advertisement for Test-Driven Development: in TDD, it is actually impossible for untested private methods to exist. The only way for a private method to be introduced into the system, is by extraction from an already tested public method. (Actually, in TDD, it is impossible for any untested code to exist, so the statement that it is impossible for untested private methods to exist is trivially true.)
In general, private methods usually are created by extracting them from a public method that has become too big or too complex. The nice thing about this is that the Extract Method Refactoring has a very convenient property: like all other Refactorings, it doesn't change the externally observable behavior, but unlike many other Refactorings, which entail rather significant changes to the internal logic (e.g. the Null Object Refactoring or the Replace Conditional With Polymorphism Refactoring), it does not change the internal logic, either. It just shuffles code around. (In fact, with a good optimizing compiler like the one in Rubinius, IronRuby or JRuby, the calls to the private methods will probably be inlined, so that the code that gets actually executed is 100% the same both before and after extracting the methods.)
So, if your code was tested before you moved into a private method, then it is guaranteed to still be tested after you move it.