my dog learned polymorphism*
The moose likes Testing and the fly likes Loosen access modifiers or use a more powerful test library to test private methods? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Engineering » Testing
Bookmark "Loosen access modifiers or use a more powerful test library to test private methods?" Watch "Loosen access modifiers or use a more powerful test library to test private methods?" New topic
Author

Loosen access modifiers or use a more powerful test library to test private methods?

Marco Ehrentreich
best scout
Bartender

Joined: Mar 07, 2007
Posts: 1280

Hi folks,

I'm trying to get more involved in unit testing, but one issue I'm still not sure of is a good way for testing private method. I'd like to hear your practical experiences with this!

On the one hand I absolutely agree that more testable code in general leads to better overall design. But on the other hand I also agree with those who say that's it's just a technical inability of available test libraries that you can't easily test for example static or private methods.

I understand that it should be possible to test private methods indirectly to some degree by invoking tests on the public API of a class. But in my experience it's often complicated or even impossible to reach full or high test coverage with these indirect tests. Of course it would be a quick solution to make such methods (maybe temporarily) public or package protected to be able to test them directly. But to be honest this looks like an ugly "solution" to me if I had good reasons to actually make a method private before. In the latter case I see it definitely just as a workaround for a weakness of JUnit and other test libraries.

Obviously there are test frameworks available today which solve the technical issues when testing private or static methods. But similar to good or bad application design I guess this fact doesn't mean that it's always "the right way" to use these tools blindly. And that's exactly what I'm still unsure of.

What do you think? Should we use more powerful test frameworks to be able to test ANY kind of code if there are good reasons for the code to be as it is (containing private and static methods etc.)? Or do you think it shouldn't be necessary to test private methods anyway?

Thanks in advance!

Marco
Jeanne Boyarsky
internet detective
Marshal

Joined: May 26, 2003
Posts: 30085
    
149

I have no problem with making methods package private to unit test them. Rendering this a moot point. What is your concern about loosening the access? Do you not trust the code in the package to avoid calling such methods?


[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
Marco Ehrentreich
best scout
Bartender

Joined: Mar 07, 2007
Posts: 1280

Hi,

the only problem I can imagine here regarding access privileges is, that package private methods could not only be overridden by my own code but instead by any other code in the same package. This could be something I haven't expected when creating a method. To avoid this scenario I would have to make all these methods final.

But you're right, maybe this is just too paranoid. Technically access modifiers could be by-passed anyway. I know there are pros and cons regarding these problems, but in my opinion it just doesn't feel right that you have to worry about testability issues in your production code. The same goes for static methods which should be avoided in many cases just because they are more difficult to test.

In the end that's really no big deal. I'm sure you can easily get used to making methods package private instead of private. I just wanted to hear some opinions on that

Marco
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Marco Ehrentreich wrote:Of course it would be a quick solution to make such methods (maybe temporarily) public or package protected to be able to test them directly. But to be honest this looks like an ugly "solution" to me if I had good reasons to actually make a method private before. In the latter case I see it definitely just as a workaround for a weakness of JUnit and other test libraries.


After more than ten years of using JUnit - of which the last eight have been on a one million lines of code project -, I've yet to come across a case in which finding a way to make a complex method public so that it actually makes sense design-wise hasn't improved the overall design.

So, I have good reason to think that there is no good reason to have a complex private method. I'm happily willing to discuss potential counter examples.


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
Marco Ehrentreich
best scout
Bartender

Joined: Mar 07, 2007
Posts: 1280

First to put one thing straight: I'm definitely lacking enough experience with unit tests - compared to you Thus I don't have a real-life example to discuss here.

Let me rephrase your statement, just to be sure I got this correctly. You say in a well-designed application there shouldn't exist any private method which is too complex to get tested indirectly by invoking tests on the public API. Did I get this right? Well, that would make perfect sense to me... Perhaps you could clarify this (for beginners :mrgreen.

Originally I was concerned with changes to production code just to make it testable. Testing private methods was just an example which probably everyone new to unit tests encounters. If you're in such a situation because there is really a problem with the design of the production code then I absolutely agree with you that it may improve the testability and even the design to make a complex method public. But it still doesn't seem right to me to make access modifiers less restrictive ONLY to make code testable. What's your opinion on this?

Marco

Jeanne Boyarsky
internet detective
Marshal

Joined: May 26, 2003
Posts: 30085
    
149

Marco Ehrentreich wrote: But it still doesn't seem right to me to make access modifiers less restrictive ONLY to make code testable. What's your opinion on this?

My opinin is that it's a tradeoff. I'd rather not have to jump through reflection hoops.

My opinion varies a bit from Ilja's. I view public methods as the API. Especially on component/library code I am sharing. If someone is going to call something package private, they are going to have to jump through hoops. They run the risk of that "non-public" API changing. And I'm not going to support problems they have if they deviate from the public API.

At the beginning I'd put a comment "// for testing only" on the package private methods. I stopped doing that after a while as everyone on the team knows what they are for.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Jeanne Boyarsky wrote:
My opinion varies a bit from Ilja's. I view public methods as the API. Especially on component/library code I am sharing. If someone is going to call something package private, they are going to have to jump through hoops. They run the risk of that "non-public" API changing. And I'm not going to support problems they have if they deviate from the public API.


You are right - we are doing this differently.

To me, there is a big difference between public and published (see http://martinfowler.com/ieeeSoftware/published.pdf). For the latter, we use a home grown Published annotation. If someone (outside our team) is going to call something that's not @Published, I'm not going to support problems they might have when it changes.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Marco Ehrentreich wrote:
Let me rephrase your statement, just to be sure I got this correctly. You say in a well-designed application there shouldn't exist any private method which is too complex to get tested indirectly by invoking tests on the public API. Did I get this right? Well, that would make perfect sense to me... Perhaps you could clarify this (for beginners :mrgreen.


Exactly. If a private method is that complex, the class probably violates the Single Responsibility Principle - it is responsible for more than one thing, most probably even at different levels of abstraction. Move the private to a class where it is naturally public (which might need the creation of a new class), and you can easily test it, and have improved the design at the same time.
Marco Ehrentreich
best scout
Bartender

Joined: Mar 07, 2007
Posts: 1280

Hi Jeanne and Ilja,

thank you very much for your answers! Your thoughts really helped me and it encouraged me to see that there are different ways to look at those problems - even amongst experts
My opinion varies a bit from Ilja's. I view public methods as the API. Especially on component/library code I am sharing. If someone is going to call something package private, they are going to have to jump through hoops. They run the risk of that "non-public" API changing. And I'm not going to support problems they have if they deviate from the public API.

I think, you're right. If you're creating libraries for others you have to be more careful what is be public and what is not. I guess this is similar to the pros and cons of a defensive programming style.
To me, there is a big difference between public and published (see http://martinfowler.com/ieeeSoftware/published.pdf).

This sounds interesting. Thanks for the link. Maybe this subtle distinction is one important reason for the problems I had thinking about solutions for the public/private problem.
Exactly. If a private method is that complex, the class probably violates the Single Responsibility Principle - it is responsible for more than one thing, most probably even at different levels of abstraction. Move the private to a class where it is naturally public (which might need the creation of a new class), and you can easily test it, and have improved the design at the same time.

This makes sense! As I'm always concerned with clean application design I'm going to look more carefully for design problems here in the future whenever I experience trouble with hard to test code. If this helps to make the code testable and improve the design at the same time this is even more worth the effort for creating unit tests.

Marco

Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
In fact, it is commonly said that Test Driven Development is a *design strategy* - the tests are just a nice side effect.
Marco Ehrentreich
best scout
Bartender

Joined: Mar 07, 2007
Posts: 1280

Really nice side effect and very interesting design strategy

Just as you mentioned it, in fact I've been trying for some time now to get started with TDD but sadly I often have to give up the TDD strategy because I sometimes simply don't know how to proceed with helpful tests that drive the design of my production code.
Do you think it's helpful for TDD to gain some more experience with unit tests in general or is this maybe even counterproductive regarding TDD? Would it be better to put more effort in directly learning TDD? (I know it's a bit off-topic now)

Marco
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
My gut says that TDD and "code driven testing" are different enough that learning the latter probably doesn't help much with the latter. You might even learn some bad habits, I'd guess. ;)

So, my advice would be to concentrate on learning TDD. What is your biggest obstacle in this regard?
Marco Ehrentreich
best scout
Bartender

Joined: Mar 07, 2007
Posts: 1280

You might even learn some bad habits, I'd guess. ;)

This is exactly what I worried about! So I trust your experience and focus on pure TDD
What is your biggest obstacle in this regard?

The first big obstacle was that I didn't really know what I wanted to test and how to write a test for it. After experimenting some time with unit tests I figured out that the reason for this problem was simply that I was used to start programming "something" without thinking about the problem long enough to know exactly what was the requirement (bad habits here, too). I guess, i need some more experience regarding this issue but I can come across this problem on my own.

At the moment the biggest obstacle I have when trying to do TDD is how "to drive" the code and design with tests. Most of the time I have the impression that I already have the finished solution in my head and I should pretend to myself that I don't know the solution. Then I try to come up with some tests which lead to the solution (i.e. implementation) I already had in mind before. I guess that's not exactly what's meant by "driving the code towards a solution". Do I just need some more practice to free myself from these ideas I already have in mind before I even start writing tests? I doubt that it's possible to ignore everything you already know though... On the other hand I'm pretty sure this anticipates the goals of test driven development to implement exactly what you need and nothing more and to implement it correctly.

Any advices how I to do TDD the right way? Or at least how to practice how to do it the right way?
Jeanne Boyarsky
internet detective
Marshal

Joined: May 26, 2003
Posts: 30085
    
149

Ilja,
I agree public vs published is an important concepts. For large components, we have agreement that only one package (the API) will be supported. For libraries, we don't have agreement outside our team. Which makes things hard to enforce.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
I often already have an idea of what the solution will look like when I start. I still try to think of the next simplest test that would fail, and then the next simplest change to the production code that would make it pass (plus refactoring, of course). And sometimes I'm pleasantly surprised to find an even simpler solution on the way. Of course I'm also not disappointed when the result is exactly the way I assumed it would... ;)
Marco Ehrentreich
best scout
Bartender

Joined: Mar 07, 2007
Posts: 1280

Too bad that there seems to be no real solution to my problems. At least it's great to hear that you have to deal with similar problems. I think I'm going to put a lot more effort in TDD and hope that I can deal better with such situations when I should forget about solutions I already have in mind in the future.

Marco
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Frankly, I don't see it as a problem at all. I don't think it's possible, or even desirable, to not think in advance. And as long as I'm happily willing to discard my clever ideas should the application of TDD allow me the emerging of a simpler solution, I don't feel troubled by it at all.

It takes some practice, though. And one of the most important practices probably is to do really, really tiny steps when you start doing TDD. If you think the steps are reasonably sized, they are probably too big. ;)

For example, if you think you will need a for loop, your very first step should most certainly be a single hardcoded value. Don't settle for a loop before it's really the simplest solution you can think of to make your tests pass.
Marco Ehrentreich
best scout
Bartender

Joined: Mar 07, 2007
Posts: 1280

Your description of the problem with too big steps is exactly what I often experience. In these situations I'm absolutely unsure if you can call this still TDD what I'm doing then. I'm pretty sure that my steps are too big most times but it's really difficult for beginners to judge what is "too big". It often seems too simple or funny to start with hardcoded values etc. although I actually know that it would be better. Maybe I should try to be more disciplined in the future...

Do you happen to know any good articles or tutorials which show some concrete examples? Although I've already read some books and articles on this topic I think it would be most helpful to see even more code examples. Every example in the books I've read was really well understandable but despite this it's often hard to use this knowledge in my own applications. Any help would be appreciated I think I'm going to buy "Growing Object-Oriented Software" by Steve Freeman and Nat Pryce. The online preview of the book looks really promising as it explains TDD with practical applications which aren't too simple to be realistic.

Marco
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Loosen access modifiers or use a more powerful test library to test private methods?
 
Similar Threads
How does Architecture fit with Agile?
web-testing
New Automation Testing Tool
what I can do with junit ??
Code and design quality vs. testability