This feels like the same conversation we had earlier this week about
accessing private methods. :) But maybe there are still a few new
points that can be made.

Tom (>>), Moritz (>):
>> I need to test some private routines, so is there a way to do that?
>
> The easiest way to do that is when the class with the private methods
> trusts the class that calls them. See for example
> http://doc.perl6.org/type/Metamodel::Trusting
> http://design.perl6.org/S12.html#Trusts
> https://github.com/perl6/roast/blob/master/S12-attributes/trusts.t

I would consider all usages of `trusts` a code smell, if nothing else
than for the reason that it links your upstream producer (your class)
to a downstream producer (your tests), and explicitly talking about
something downstream creates an unholy coupling to it, *and* is
difficult because you have to predeclare it in some way.

> But you should ask yourself if you really, really want this.
>
> And then you can also do something like:
>
> my $private_method = $obj.^private_method_table{$methodname};
> $obj.$private_metnod(arguments here)
>
> but it is rather questionable use of the MOP.

I would actually use $obj.^find_private_method, as I showed in that
other thread:

    class C { method !foo { say "OH HAI" } }; my $obj = C.new; my $pm
= C.^find_private_method("foo"); $obj.$pm

But I would also amend moritz' "rather questionable" by saying that if
you do this, even from the comfort of your own tests, you waive
certain advantages of good OOP that you then won't get back.

That little '^' means "time to cheat" -- if private methods are the
walls of a labyrinth preventing you from going wrong, the '^' just
took you to "cheat mode" and you can survey the whole labyrinth from
above. In my opinion, tests shouldn't have to resort to that. A very
small list of things require cheat mode. Tests don't.

The reason we deal with all this inside/outside stuff and make some
things private, is so that we can reserve the right to evolve them
without breaking anything on the outside. Like a
<https://en.wikipedia.org/wiki/Ball_bearing>, the insides are supposed
to be able to move without creating any friction on the outside.

Any kind of coupling with the outside makes that kind of frictionless
evolution harder. Going to the MOP to break the privacy couples the
tests to the implementation.

Beyond that, this simply *shouldn't need to happen* if the tests are
written by the same person as the implementation.

(A) Either you need to test the method, and then it can happily be
made public, or be made an our sub, or a sub outside of the class.
(B) Or you keep the method private, but find some other way to test it
besides calling it directly.

The goal here is to write tests that don't break in the future. In a
way, this is what good OOP leads to. Coupling your tests to private
methods is a mistake, IMHO. Perl 6 makes this difficult because it's
not a good idea.

// Carl

Reply via email to