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.
Related
As mentioned in this answer, in Ruby 2.1 or later, this code:
class SimpleTest
private
define_method :foo do
42
end
end
will define foo as a private method of SimpleTest instances. (In Ruby 2.0 and earlier it won't be private.) However, I'm looking to do something a little less trivial. I would like to define a DSL that classes can extend, and would like the methods that the DSL defines internally to respect the private/protected visibility of the calling context. That may not be clear, so here's an example:
module Dsl
def has_a(name)
define_method name do
42
end
end
end
class Test
extend Dsl
private
has_a :thing
end
As written, that code will define a public thing method on Test instances. Instead, I would like has_a to be able to reflect on the method visibility where it was called (private in this case), and define thing under that same method visibility.
I'm not familiar with Ruby's C source code, but I took a quick look and found this function which seems like it might do what I want, but I don't think it's accessible from Ruby. (It seems to only be used here.) I also looked up the documentation for define_method (since the first example works as desired) here and it seems like the noex variable declared and set here:
int noex = NOEX_PUBLIC;
const NODE *cref = rb_vm_cref_in_context(mod, mod);
if (cref) {
noex = (int)cref->nd_visi;
}
could be the value I want, but again I don't know how I would get that in Ruby, or even if it would be able to reflect back on the calling scope (in Test). Assuming I had the visibility, then I could simply call private name (or protected name) after the define_method call inside has_a if it wasn't called in a public context.
Thoughts? Is there any way to do this, or am I out of luck?
I think this question has a similar answer to what you are looking for: https://stackoverflow.com/a/28075865/5129208
It looks like the author of that made a custom module to get the behavior you're after.
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 read that "puts" is a private instance method of the module Kernel (and therefore of Object, since Object mixes in Kernel).
That's why when we call puts, we don't specify a explicit receiver. My question is, if it's a private instance method, how is it possible that we can call it from any other scope? So, we can do:
class Test
puts "hello" # self is Test. So, we are calling self.puts "hello" -
end
What am I missing here? How is it possible that this works? We are calling a private instance method?
EDIT:
Same question arises if I do this:
class Object
private
def talk
puts "hi there"
end
end
class Test
talk # outputs 'hi there'
end
Why is it possible that from class Test we can call a private method from the class Object?
Please have a look at the doc for the Kernel module - http://www.ruby-doc.org/core-2.0.0/Kernel.html.
Unlike Java, Ruby is not limited to Classes as containers of implementations. Modules act as wonderful containers which can be mixed into other classes. When a module is mixed into another class, all its instance methods become instance methods of those class. Since the Kernel module is mixed into the Object class, its methods are therefore available in all Ruby classes.
Please read the following:
Ruby access control
Common misunderstanding and clarification about access controls in Ruby
With the risk of duplication, I have to say this: private in Ruby is not the same as in C++ or Java. Subclasses of a class can call private methods declared in their superclass. In fact, you can call private method of any class using :send. The only difference between private and protected methods is that private methods can't be called with explicit receivers.
Even the last rule has an exception. If your private method is something like age=, it can (and has to be) called with self. Funny, isn't it? :)
UPDATE: (to explain the gist):
The talk method which you wrote in your code above is being called on the main object which is the context for all Ruby programs. It's not being called on the Test class which is why it's not working for your second gist.
In the gist that I have provided, talk is a private class method which is why it gets executed at the time of class definition. In the same gist, the talk2 method is an instance method and can only be called from within instance methods. Your example gist didn't work because you were trying to invoke an instance method at the time of defining the class.
I don't understand why such long answer as in the other answer is required, or is upvoted. The answer to your question is simple.
It is because almost all classes (i.e., anything other than BasicObject) includes Kernel. Therefore, in the scope of a usual object, Kernel class is inherited, and hence its methods are accessible. That is all.
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.
This is not specific to Ruby, but I happen to be using Ruby at the moment.
Here is a class that provides text printing functionality.
class Printer
# some static methods
def self.fancy_print(text)
# do fancy formatting
end
def self.print(text)
fancy_print(text)
end
# some instance methods
def initialize(text)
#text = text
end
def print
#somehow call fancy_print(#text)
end
end
Is it bad design to provide both instance and static methods in a class?
Sometimes I would like to keep several instances of Printer lying around. Other times, I just need to say Printer.print(text) and just grab that text without bothering to store it for later, hence resulting in a static print method and an instance print method.
No, it's not bad design.
It's completely normal–some methods are class methods, some are instance methods. I'm not sure what the perceived issue might even be. It's somewhat difficult to even find classes with only one or the other, although in Java you frequently see static utility classes.
Edit IMO the question is misleading; you're actually asking if it's bad design to have static and instance methods of the same name.
It's tricky if both are public because it isn't necessarily obvious how to use the class. In other words, is it designed to be used via the static, or instance method? Both? What's different about them? Should that difference be... differentiated by a name?
Ultimately it depends on context and usage–there's no single answer.
That's okay, I think. Here's how you would code the Printer#print method
class Printer
def print
self.class.fancy_print(#text)
end
end
There is nothing wrong with having class methods and instance methods for a specific class, as long as they make sense belonging to the class.
I.e. what does fancy_print do? Is it something specific to the Printer class. If it is, then you shouldn't worry.
On the other hand, if it is to be used for any string value, you can do something cheekier, i.e. adding this method to the string class
String.class_eval do
def fancy_print
## implementation
end
end
Now you can do "Hello".fancy_print
Hope this answer was of any use. Also write test cases!