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

testing private methods with junit?

No�l Verdurmen
Ranch Hand

Joined: Jul 28, 2004
Posts: 33
Hello

is it possible to test private methods with JUnit? How?
Or is testing private methods something that is not desirable?

Thanks


No�l
Lasse Koskela
author
Sheriff

Joined: Jan 23, 2002
Posts: 11962
    
    5
Originally posted by Noel Verdurmen:
is it possible to test private methods with JUnit? How?

Yes, it is possible through the Java Reflection API, for example. Here's a nice article explaining some ways to approach testing private methods:
Testing Private Methods with JUnit and SuiteRunner

Having said that...
Originally posted by Noel Verdurmen:
Or is testing private methods something that is not desirable?

There are a number of people who (myself included) believe that you shouldn't need to test private methods. Why? Because a unit test is supposed to test a unit's behavior which is exposed through public methods (which in turn invoke the private methods as necessary). If you have a private method which you want to test, it should probably be moved into a new class as a public method.

I'm sure others will chime in with their views on the subject. (this has been discussed oh so many times before )


Author of Test Driven (2007) and Effective Unit Testing (2013) [Blog] [HowToAskQuestionsOnJavaRanch]
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
I agree with Lasse - the need to test a private method is a design smell, probably your class is too complex.

Can you please explain why you want to test a private method? What is the method doing and what class is it part of?


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
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24187
    
  34

I'm not going to enter into the discussion of whether or not private methods should be tested, except to say that it certainly happens that a method you think ought to be private needs to be independently testable. Besides reflection, there are two other approaches worth considering:

First, consider making the method package-local instead of private. Is it evil to make methods accessible just for testing? Some people would say so; other people (myself included) can be more pragmatic about it. If I had a choice between exposing a method within a package for testing, or writing and maintaining horrifyingly ugly reflective testing code, I'd choose the former as the lesser of two evils.

Second, consider making the test case a static nested class inside the class under test. This is nice because the nested class has access to all the outer class's methods, and yet they can still be private. It may be ugly to have the test case in the same file as the main class, but note that it doesn't have to be shipped and adds nothing to the size of the outer class's .class file.

I've used both of these techniques; I actually tend to prefer the first. So I find myself using not many private methods, and more numerous, smaller packages to regain the lost encapsulation. This is actually a good thing, on balance.


[Jess in Action][AskingGoodQuestions]
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Ernest Friedman-Hill:
It may be ugly to have the test case in the same file as the main class, but note that it doesn't have to be shipped and adds nothing to the size of the outer class's .class file.


I don't think this is fully true. Remember that for the VM there are only top-level classes, so for inner classes to be able to access private members of the enclosing class, the compiler has to create synthetic access methods with less restrictive visibility modifiers, if I remember correctly.
Frank Carver
Sheriff

Joined: Jan 07, 1999
Posts: 6920
Ernest writes: First, consider making the method package-local instead of private. Is it evil to make methods accessible just for testing?

By the same logic, also consider making the method public. Adding unit tests to a unit test suite effectively "pins down" the interface and behaviour of a method, and it must be independently usable for the test to work, so why not just make it available to callers?

Can you explain why you thought it necessary to mark it private in the first place?


Read about me at frankcarver.me ~ Raspberry Alpha Omega ~ Frank's Punchbarrel Blog
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24187
    
  34

Originally posted by Ilja Preuss:
[F]or inner classes to be able to access private members of the enclosing class, the compiler has to create synthetic access methods with less restrictive visibility modifiers


Of course, you are right. Thanks for pointing this out!
No�l Verdurmen
Ranch Hand

Joined: Jul 28, 2004
Posts: 33
Thanks for all the answers !

I asked this, because I have a helper method that is only necessary in one class (thus private), but this method contains some bit-manipulating code and I am not 100% sure about it.

No�l
No�l Verdurmen
Ranch Hand

Joined: Jul 28, 2004
Posts: 33
Originally posted by Ilja Preuss:
I agree with Lasse - the need to test a private method is a design smell, probably your class is too complex.

Can you please explain why you want to test a private method? What is the method doing and what class is it part of?


I have a data access class, in which I need to convert byte arrays into an int.
Frank Carver
Sheriff

Joined: Jan 07, 1999
Posts: 6920
I have a helper method that is only necessary in one class (thus private)

In my opinion, just because something is only used by one class at the moment is no particular reason to make it private. A good reason for making a method private is when it contains only part of an algorithm or process, and will not work if called independently. If your method represents a useful, separate idea, why not make it public? Then it will be available for use from your other code if you need it.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
I agree with Frank. I would even go a step further and move the method to a different class, for example one named ArrayUtilities or something.
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24187
    
  34

If you're writing a standalone application or system, this is all well and good. If, perchance, you're writing a library or library-like tool, then you need to think twice about making something available that you are not prepared to support.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Ernest Friedman-Hill:
If you're writing a standalone application or system, this is all well and good. If, perchance, you're writing a library or library-like tool, then you need to think twice about making something available that you are not prepared to support.


Yeah, the old public vs. published problem...
Ted Young
Greenhorn

Joined: Aug 10, 2004
Posts: 6
How about legacy code? By legacy code, I refer to code that has little or no unit tests. I've found that in order to support refactoring, etc., I need unit tests. I can't refactor the code to get rid of the private methods until I have unit tests, so I've found that I need to use workarounds to access the private methods (and in some rare cases, the private instance variables).

Has anyone else run into this same issue and had a different solution? Are there any other cases where unit testing private methods is the only way to go?

;ted
Lasse Koskela
author
Sheriff

Joined: Jan 23, 2002
Posts: 11962
    
    5
If you're feeling stuck trying to write tests for the legacy code, try taking a step back and see if you could add an abstraction layer in between the new codebase and the legacy codebase which you can write tests for.

A coworker of mine recently asked me to look into how he could test something that proved to be a lot of work and resulting in monstrous tests. The approach we came up with was to stop writing those tests and moving onto a higher level -- doing larger-grained tests which happened to be easier to write. (I don't know how it panned out in the end, but it looked like a viable solution for getting unstuck)
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Ted Young:
[QB]How about legacy code? ...

Has anyone else run into this same issue and had a different solution?


As Lasse already said, one "solution" is to write higher level tests instead of unit tests.

You might also want to take a look at http://www.objectmentor.com/resources/articles/WorkingEffectivelyWithLegacyCode.pdf
Ted Young
Greenhorn

Joined: Aug 10, 2004
Posts: 6
Originally posted by Lasse Koskela:
[QB]If you're feeling stuck trying to write tests for the legacy code, try taking a step back and see if you could add an abstraction layer in between the new codebase and the legacy codebase which you can write tests for.


That's a good idea that works well if the legacy code is granular enough. The problem that I'm dealing with (and solving in unit tests by accessing private fields) is that the public interfaces are not granular enough, i.e., one method that does everything instead of a number of more fine-grained methods.

I guess I could just go ahead and make the private methods public, but that doesn't help with the (admittedly separate) issue of needing a safety net of passing unit tests before refactoring the monster methods.

;ted
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Ted Young:
That's a good idea that works well if the legacy code is granular enough. The problem that I'm dealing with (and solving in unit tests by accessing private fields) is that the public interfaces are not granular enough, i.e., one method that does everything instead of a number of more fine-grained methods.
[/QB]


But your abstraction layer could be more granular than the legacy code, couldn't it?
Juan Rolando Prieur-Reza
Ranch Hand

Joined: Jun 20, 2003
Posts: 236
Originally posted by Lasse Koskela:
...you shouldn't need to test private methods....


Lasse,
Even though you establish a sound policy of not testing private methods
(because you should only test outward behavior), consider this:
You may need to affect the state of an object in order to test a public method, and it could happen that the only way to do so is to invoke
a private method. You want to use the private method
as part of your test, but not test it
.

Silly example:
Test the public method addSome( smallN) that updates a private counter.
You want to see if it behaves properly when the private counter
turns to a value near Integer.MAX_VALUE (or a large Float or something).

You don't want to invoke the addSome() a zillion times just to get the counter up to a value
where it might overflow on the next call.
So, in this case I would either use your suggestion involving reflection,
or make the method protected, or something like that, to set up the test.

Cheers!


Juan Rolando Prieur-Reza, M.S., LSSBB, SCEA, SCBCD, SCWCD, SCJP/1.6, IBM OOAD, SCSA
Juan Rolando Prieur-Reza
Ranch Hand

Joined: Jun 20, 2003
Posts: 236
Originally posted by Lasse Koskela:
... Here's a nice article explaining some ways to approach testing private methods:
Testing Private Methods with JUnit and SuiteRunner ...


Just for the record, This article presents 4 approaches to testing
private methods very nicely (actually 2 approaches).
But it does not mention the approaches that I happen to use most of all:

Change private members to protected, and use a subclass for testing.


I say it only gives 2 approaches because (1) says dont do it at all, and (3) says to introduce an inner (static) test class in the class to be tested. But then the class under test is no longer the same; it has been
radically changed, increased in complexity and added opportunities for coding errors. Although changing private to package or protected changes the class (you might argue), those changes do not introduce new behavior and are rather gentle changes (especially the protected alternative).

Finally, the article advocates reflection (and I'm sure I'll use that).
But, I would not rely on reflection for production system testing because
JIT JVMs do things that might thwart reflection, thus ruining your tests
.
[ August 16, 2004: Message edited by: john prieur ]
Lasse Koskela
author
Sheriff

Joined: Jan 23, 2002
Posts: 11962
    
    5
If you really need to call a private method from a test, make it package private (if your tests are in the same package as the class under test) or public. I don't mind doing that, although some consider it "wrong" to expose methods just for the sake of testing.

If you have a concrete example, I'd love to try and solve the "private method problem". (if you do, please use the CODE tags when posting...)
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by john prieur:
Silly example:
Test the public method addSome( smallN) that updates a private counter.
You want to see if it behaves properly when the private counter
turns to a value near Integer.MAX_VALUE (or a large Float or something).


That we can't easily test this is a sign that we should change the design.

What I could imagine doing is changing the private counter field from an int (or something) to an instance of a Counter class. Now we only need to test that addSome is using the counter class correctly (for example by mocking it) - and to seperately test the Counter class. I wouldn't hesitate to give the Counter class a constructor for an explicite starting value, then.

Does that sound reasonable?
Vladas Razas
Ranch Hand

Joined: Dec 02, 2003
Posts: 385
I will present my live code. Anyone can then say should the method be other than private and how to test this. Or how I should design that to make it testable. The class Validator (in my implementation it's singleton) which has a map of all "validations". It's purpose is to pass validate request to appropriate validation object (depends on validation class name passed) if it's already in map and create one if it is not in map.



I am talking about retrieveValidation method. It's complex enough to deserve testing.
Vladas Razas
Ranch Hand

Joined: Dec 02, 2003
Posts: 385
Ok. it shall "return validation;" That's another reason to test it. It's not yet finished
Vladas Razas
Ranch Hand

Joined: Dec 02, 2003
Posts: 385
Though maybe I could move all that caching object/lazy instantion map functionality to the separate class. Maybe even "re-use" it later
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Vladas Razas:
Though maybe I could move all that caching object/lazy instantion map functionality to the separate class. Maybe even "re-use" it later


Yes - that's what I would do.
Vladas Razas
Ranch Hand

Joined: Dec 02, 2003
Posts: 385
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: testing private methods with junit?