Visibility in tests

Hi, I’m new to this, forum, but I really love Ruby and I hope this is
the right place to discuss problems and questions I have. I learned Ruby
when I was twelve, so I know Ruby for more than one third of my life and
I now call it my “mother tongue” of programming languages, but I mostly
programmed rather childish stuff and for a long time, I was not
interested in learning more than the basic stuff, since I could just do
everything I wanted with that already.

However, in the last few months, my Ruby programming has grown a little
more serious, and (among other things) I started for example to write
tests for all of my programs that included more than 100 lines, even for
private purposes. Usually that went quite well, but there stumbling
block in my way that annoyed me multiple times, so I decided to ask some
people who maybe know a little more about Ruby.

I don’t know how to apply unit tests to private methods. Usually, I only
use very few private methods and for my small private purposes, it was
okay to just set those few to public, too, but how do you do that in a
good way, if you really do have good reasons for making the methods
private?

Another small question: Do you know where I can find Ruby style
guidelines or something like that?

On Apr 6, 2010, at 17:26 , Bernhard B. wrote:

I don’t know how to apply unit tests to private methods. Usually, I only
use very few private methods and for my small private purposes, it was
okay to just set those few to public, too, but how do you do that in a
good way, if you really do have good reasons for making the methods
private?

easy! make them public!

Either don’t make them private in the first place (my preference) or
make them public in your tests (second choice… usually when I’m
working with inherited code):

class X
public :previously_private_method
end

class TestX < MiniTest::Unit::TestCase
def test_previously_private_method

end
end

Ryan D. wrote:

On Apr 6, 2010, at 17:26 , Bernhard B. wrote:

I don’t know how to apply unit tests to private methods. Usually, I only
use very few private methods and for my small private purposes, it was
okay to just set those few to public, too, but how do you do that in a
good way, if you really do have good reasons for making the methods
private?

easy! make them public!

Or use one of:

obj.send(:private_method_name, args…)

obj.instance_eval { private_method_name args… }

Note that the latter also switches the object context so that ‘@foo
inside the block means the @foo instance variable inside obj. That can
be useful too.

Ryan D. wrote:

On Apr 6, 2010, at 17:26 , Bernhard B. wrote:

I don’t know how to apply unit tests to private methods. Usually, I only
use very few private methods and for my small private purposes, it was
okay to just set those few to public, too, but how do you do that in a
good way, if you really do have good reasons for making the methods
private?

easy! make them public!

Either don’t make them private in the first place (my preference) or
make them public in your tests (second choice… usually when I’m
working with inherited code):

class X
public :previously_private_method
end

class TestX < MiniTest::Unit::TestCase
def test_previously_private_method

end
end

Okay, thanks, a lot, nice and easy idea, I should have seen that. :slight_smile:

Brian C. wrote:

Ryan D. wrote:

On Apr 6, 2010, at 17:26 , Bernhard B. wrote:

I don’t know how to apply unit tests to private methods. Usually, I only
use very few private methods and for my small private purposes, it was
okay to just set those few to public, too, but how do you do that in a
good way, if you really do have good reasons for making the methods
private?

easy! make them public!

Or use one of:

obj.send(:private_method_name, args…)

obj.instance_eval { private_method_name args… }

Note that the latter also switches the object context so that ‘@foo
inside the block means the @foo instance variable inside obj. That can
be useful too.

Thanks a lot, I think the possibility to access instance variables from
outside will also be very useful for other purposes. Okay, now I will
have no problems anymore to write tests for private methods.^^

I’m going to guess that I’m the odd one out here, but…

On Tuesday 06 April 2010 07:26:20 pm Bernhard B. wrote:

I don’t know how to apply unit tests to private methods. Usually, I only
use very few private methods and for my small private purposes, it was
okay to just set those few to public, too, but how do you do that in a
good way, if you really do have good reasons for making the methods
private?

Don’t test them directly.

Well, alright, let me take a step back: I agree with Ryan here that they
shouldn’t be private at all. In a language like Java, I can understand,
but in
Ruby, your users will have the source code, and even if they don’t,
they’ll
have Object#send and instance_variable_get/set.

Your best bet is to explicitly document your public API. If people use
methods
that aren’t documented, they get to keep both pieces.

However, there are exceptions – if I recall, Rails will automatically
make
certain methods inaccessible to mass assignment if they’re private or
protected.

Anyway…

Presuming you really do have a good reason for making them private, you
probably have an even better reason to not unit test them directly, and
certainly not to rely on the state of instance variables in your unit
tests.

Your tests should verify behavior, not the minute details of state.

As an example: I realize this is about the worst way to do things, but
let’s
pretend you have the following methods on Integers:

public
def is_prime?
factors.empty?
end
private
def factors

end

Now, your tests should be testing what you actually care about, not
how
it’s implemented. So, instead of testing factors directly, you would
test
is_prime. Your tests would look something like this:

it ‘should believe 4 is prime’
5.should be_prime
4.should_not be_prime

end

I realize this makes them more integration tests than unit tests, and
maybe
I’m missing the point, but I just don’t see the use of such fine-grained
tests. You want them fine-grained enough to actually catch bugs, but
coarse
enough that they’re actually worth writing.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs