aspose file tools*
The moose likes Testing and the fly likes Testing private method Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Engineering » Testing
Bookmark "Testing private method" Watch "Testing private method" New topic
Author

Testing private method

vu lee
Ranch Hand

Joined: Apr 19, 2005
Posts: 189
I need to modify a legacy class which has two public methods and 15 private methods. This is a complex class since upon initializing, it create three jms listeners and sync up tables between two databases. Now, I creates an additional private method, and would like to run some junit test, but I have no way to access the method. I could invoke a public method which, in turn, invokes the new private method, but it could take a while to reach the private method. I cannot make the method public and protected since it would break OOP. I cannot make the method package private since I am not allowed to put the test code in the domain package. Using reflection would be quite complex since I need to initialize some internal objects.

I was thinking about
1. Within the private method, create and invoke a new class which contains code to get the job done. I could then do junit test on the new class. e.g
private String performA(){
DelegateClass delegate = new DelegateClass(myObject1,myObject2);
return delegate.performA();
}


2. changing private method to public static method whose parameters contain collaborator objects. I could use EasyMock to create these collaborator objects to run junit test.
public static String performA(MyObject1 myObj1, MyObject2 myObj2){

}


Will it work? Any other suggestions.
Thanks
Jeanne Boyarsky
author & internet detective
Marshal

Joined: May 26, 2003
Posts: 30955
    
158

Originally posted by vu lee:
I cannot make the method public and protected since it would break OOP.

Fair enough. Note that both of your proposed solutions involve making the API public (or at least the one it delegates to.) That seems like it breaks OOP just as much as making the original method public.


I cannot make the method package private since I am not allowed to put the test code in the domain package.

Why not? You can put it in another physical directory with the same package name. This gives your test package access, but doesn't require you to deploy it. This is the route I lean towards since it makes it clear that the access is only intended for the tests.


[Blog] [JavaRanch FAQ] [How To Ask Questions The Smart Way] [Book Promos]
Blogging on Certs: SCEA Part 1, Part 2 & 3, Core Spring 3, OCAJP, OCPJP beta, TOGAF part 1 and part 2
Sunil Vasudevan
Ranch Hand

Joined: Mar 05, 2007
Posts: 107
There was a similar question in this forum on testing private methods.

There was a mention of PrivilegedAccessor (http://sourceforge.net/projects/privaccessor/). You can try that for unit testing.


Sunil.V<br />SCJP2, SCWCD1.4, SCBCD1.3
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by vu lee:
I need to modify a legacy class which has two public methods and 15 private methods. [...] I cannot make the method public and protected since it would break OOP.


I have two, rather orthogonal answers to your problem:

First, it's good that you worry about encapsulation (if I understand you correctly). You need to keep in mind, though, that it is a means to an end, and that it needs to be balanced against other forces. After all, a fully encapsulated class would be worthless, as it couldn't be used from the outside.

The main reason to use encapsulation is to manage code dependencies, so to make it easier to change a class while it is already in use by clients. It could be argued that tests are as important, as they help you to not change the behavior of the class in unexpected ways. Therefore it can be argued that it makes sense to violate encapsulation to some amount if it allows you to more comprehensively test the class in exchange.

Second, the existence of a lot of private methods - especially private methods that are complex enough that they need explicit testing - is a code smell in itself, a sign that there is probably a design problem. It hints at the fact that the class is likely to violate the Single Responsibility Principle, which states that a class should have exactly one reason to change (with other words, the code for different responsibilities should be decoupled by putting them into different classes).

So the desire to write a test for a private method is a hint that that method probably should be on a different class, one where it would naturally be public. This is one of the ways unit testing your code actually helps discover better designs.

Does that help?


The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
vu lee
Ranch Hand

Joined: Apr 19, 2005
Posts: 189
1.
Note that both of your proposed solutions involve making the API public (or at least the one it delegates to.) That seems like it breaks OOP just as much as making the original method public


I don't see how it breaks OOP if the DelegateClass is theadsafe, immutable, and performs defensive copy when publishing internal objects. Suppose, even if the DelegateClass is mutable and and final, could the integrity of the LegacyClass been violated?

2. awesome!
vu lee
Ranch Hand

Joined: Apr 19, 2005
Posts: 189
Thanks for the replies guys
After all, a fully encapsulated class would be worthless, as it couldn't be used from the outside.


If certain codes don't need to be used from the outside, then why expose them? My understanding is that the class should be fully encapsulated till there is a need to gradually open it.

Therefore it can be argued that it makes sense to violate encapsulation to some amount if it allows you to more comprehensively test the class in exchange.

It's true but,IMO, this should be the last approach. The question is that could we do the comprehensive tests without compromising the principle of encapsulation?

....is a code smell in itself, a sign that there is probably a design problem. It hints at the fact that the class is likely to violate the Single Responsibility Principle

I agree, but this is a core and heavy-weight legacy class which does lot of tasks... like sync-up many tables between Oracle db and MySql db. It takes lot of time to refactor and tests. Besides, I don't even fully understand what the class really does. Changing the method modifier from private to protected/public could introduce some side effects which I don't know at the moment. That is why I try to avoid it.
Jeanne Boyarsky
author & internet detective
Marshal

Joined: May 26, 2003
Posts: 30955
    
158

Originally posted by vu lee:
I don't see how it breaks OOP if the DelegateClass is theadsafe, immutable, and performs defensive copy when publishing internal objects. ... If certain codes don't need to be used from the outside, then why expose them?

I shouldn't have said it breaks OOP. You are correct that it doesn't. I was trying to respond more to the second half - the public vs published problem. While I agree with Ilja that moving the method to a new public class/method/etc is a good idea, this does allow clients to call it. Which sounds like you don't want to do - given the concern about exposing.

It's true but,IMO, this should be the last approach. The question is that could we do the comprehensive tests without compromising the principle of encapsulation?

There are different levels of encapsulation. Package private access encapsulates details to the local package. And since external clients have no business being in your package, you still retain the logical benefits of encapsulation.

Changing the method modifier from private to protected/public could introduce some side effects which I don't know at the moment. That is why I try to avoid it.

It is one of the safest refactorings there is. Initially changing the modifier to package private can't introduce any side effects since there are no outer callers.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Jeanne Boyarsky:

Initially changing the modifier to package private can't introduce any side effects since there are no outer callers.


That is, in fact, not totally true: *If* there is a subclass with a more accessible method of the same signature, making the superclass method less private suddenly makes it being overridden in the subclass. That can lead to quite strange and hard to find side effects. It's a very rare case, and most often easy to check against if you know about it, though.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by vu lee:
If certain codes don't need to be used from the outside, then why expose them? My understanding is that the class should be fully encapsulated till there is a need to gradually open it.


If we need to test the code, we *need* to use it from the outside, don't we?

I agree, but this is a core and heavy-weight legacy class which does lot of tasks... like sync-up many tables between Oracle db and MySql db. It takes lot of time to refactor and tests. Besides, I don't even fully understand what the class really does. Changing the method modifier from private to protected/public could introduce some side effects which I don't know at the moment. That is why I try to avoid it.


Yes, working with legacy code is hard. You need to find ways to make the code testable without introducing any bugs, to then be able to apply more aggressive refactorings without breaking something. In fact, there is a whole (and quite good) book about this: "Working Effectively With Legacy Code".

One of the most important insights I gained from the book is that when working with legacy code, there is no magic solution - and often enough you have to temporarily make the code worse to make it testable.
Jeanne Boyarsky
author & internet detective
Marshal

Joined: May 26, 2003
Posts: 30955
    
158

Originally posted by Ilja Preuss:
That is, in fact, not totally true: *If* there is a subclass with a more accessible method of the same signature, making the superclass method less private suddenly makes it being overridden in the subclass. That can lead to quite strange and hard to find side effects. It's a very rare case, and most often easy to check against if you know about it, though.

Good point. I didn't think of that one.

How about making it package private AND final; at least for a moment? That seems side effect proof.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Jeanne Boyarsky:

How about making it package private AND final; at least for a moment? That seems side effect proof.


Sounds like a good idea to me!
vu lee
Ranch Hand

Joined: Apr 19, 2005
Posts: 189
Thanks guys
 
It is sorta covered in the JavaRanch Style Guide.
 
subject: Testing private method