Visibility in tests

  • Thread starter Bernhard Brodowsky
  • Start date
B

Bernhard Brodowsky

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?
 
R

Ryan Davis

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
 
B

Brian Candler

Ryan said:
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.
 
B

Bernhard Brodowsky

Ryan said:
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. :)

Brian said:
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.^^
 
D

David Masover

I'm going to guess that I'm the odd one out here, but...

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top