Re: Can a user cheat and call a class's private method?
On Tue, May 12, 2015 at 11:03:01PM +0200, Moritz Lenz wrote: I'm curious, what's a case where private state of a class needs to be tested, and tests agains the public interface are not enough? In my experience, testing against private parts only makes the tests more brittle (that is, every implementation change causes test failures, even if the public interface is unchanged). Tests are supposed to be brittle so the code is not. Any routine call could be a good test point--particularly when you need to change an implementation though the public interface is unchanged. White box testing has its value. Also, are you talking about an actual Perl 6 code base that needs testing, but that is too large for a refactoring? If yes, I'd be curious where such a beast exists. The OP was Tom Browder; I was just asking about the merits of 'trust' vs. 'augment'. I have seen code where such testing would be good, but not yet in Perl 6. Thanks, Rob
Re: Can a user cheat and call a class's private method?
On 2015-05-12 12:40 PM, R. Ransbottom wrote: On Mon, May 11, 2015 at 03:22:46PM -0700, Darren Duncan wrote: you can use trusts. Also having to do this may indicate bad code design. -- Darren Duncan I saw Moritz' and Carl's responses and I agree with the smell issue. Given that the code exists and needs testing, 'augment' seems preferable to 'trust'. 'augment' avoids the predeclaration issue and simplifies the test code by removing indirection. Is class finalization implemented? Searching the synopses, I found only a mention. The other question is whether your private need to be private. Generally speaking tests should only be against a public interface, and if you really need to test something private then maybe a refactoring of the thing being tested is in order. For example splitting it into multiple classes where what was private becomes the public API of a utility consumed by the other class. Any private routines you should be able to test sufficiently indirectly by way of public routines that use them, if the code is well organized. -- Darren Duncan
Re: Can a user cheat and call a class's private method?
Hi, On 05/12/2015 09:40 PM, R. Ransbottom wrote: On Mon, May 11, 2015 at 03:22:46PM -0700, Darren Duncan wrote: you can use trusts. Also having to do this may indicate bad code design. -- Darren Duncan I saw Moritz' and Carl's responses and I agree with the smell issue. Given that the code exists and needs testing, I'm curious, what's a case where private state of a class needs to be tested, and tests agains the public interface are not enough? In my experience, testing against private parts only makes the tests more brittle (that is, every implementation change causes test failures, even if the public interface is unchanged). Also, are you talking about an actual Perl 6 code base that needs testing, but that is too large for a refactoring? If yes, I'd be curious where such a beast exists. Is class finalization implemented? I don't think so. Cheers, Moritz
Re: Can a user cheat and call a class's private method?
See Moritz Lenz' response to this thread on March 26. To summarize, you can use trusts. Also having to do this may indicate bad code design. -- Darren Duncan On 2015-05-11 2:13 PM, R. Ransbottom wrote: I need to test some private routines, so is there a way to do that? Is there a downsize to augment for this? # source class Dog { method bark { say( #bark); return bark } method !pee { say( #pee ); return pee} } # test #use MONKEY_TYPING; use Test; use v6; plan 4; my Dog $t; ok( Dog.bark eq bark, Good loud Dog ); ok( $t.bark eq bark, Good loud dog ); augment class Dog { # augment should be a test # do private tests in private ok( Dog!pee eq pee, Good bad Dog ); ok( $t!pee eq pee, Good bad dog ); }
Re: Can a user cheat and call a class's private method?
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
Re: Can a user cheat and call a class's private method?
On Fri, Mar 27, 2015 at 6:36 AM, Carl Mäsak cma...@gmail.com wrote: 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. ... Okay, Carl, I think I understand. But what about this for my particular situation (this sounds like your method A I believe): Use a separate module (but included with the code for the whole package) for the non-class-specific, formerly-private methods to be public, but the use statement for the modules would be inside the class-specific methods that need them (a new, restricted scoping in Perl 6 I understand). That actually makes more sense to me now because some of the private methods are really general math subroutines. That way I can test those subroutines without breaking OOP (I think). Best, -Tom
Re: Can a user cheat and call a class's private method?
On Fri, Mar 27, 2015 at 8:35 AM, Tom Browder tom.brow...@gmail.com wrote: Use a separate module (but included with the code for the whole package) for the non-class-specific, formerly-private methods to be public, because some of the private methods are really general math subroutines. That way I can test those subroutines without breaking OOP (I think). That's a double win, both making the larger module better organized and creating a new module of general utility. the use statement for the modules would be inside the class-specific methods that need them (a new, restricted scoping in Perl 6 I understand). Hmm, I never thought about the scoping of use in Perl 5, but that makes sense- exports in Perl 5 are into the namespace of the current package, not lexical- though a package declaration is lexical. Learn something new every day -y
Re: Can a user cheat and call a class's private method?
On Mar 26, 2015 11:04 AM, Moritz Lenz mor...@faui2k3.org wrote: On 26.03.2015 16:55, Tom Browder wrote: I need to test some private routines, so is there a way to do that ... And then you can also do something like: my $private_method = $obj.^private_method_table{$methodname}; $obj.$private_metnod(arguments here) That works great! but it is rather questionable use of the MOP. Nevertheless, it is very helpful for debugging. Thanks. Cheers! -Tom
Can a user cheat and call a class's private method?
I need to test some private routines, so is there a way to do that? Or will I have to copy code to a test script or? BTW, the tests are for input/output checks during development--not for the public user. Thanks. Best, -Tom