views:

113

answers:

5

In many application I often have algorithms which make use of dedicated sub-algorithms (or simply well defined pieces of code).

Till now, when I wrote the main algorithm, i created a private method for each sub-algorithm like in the example below (OldStyle):

public class OldStyle {

    public int mainAlg() {
        int x = subAlg01();
        int y = subAlg02();
        int z = x * y;
        return z;
    }

    private int subAlg01() {
        return 3;
    }

    private int subAlg02() {
        return 5;
    }
}

This worked fine but I didn't like having a proliferation of methods (subAlg01 and subAlg02) which, even if private, were only used by one method (mainAlg).

Recently I dicovered the use of local inner classes and now my example is (NewStyle):

public class NewStyle {

    public int mainAlg() {
        class Nested {

            public int subAlg01() {
                return 3;
            }

            public int subAlg02() {
                return 5;
            }
        }
        Nested n = new Nested();
        int x = n.subAlg01();
        int y = n.subAlg02();
        int z = x * y;
        return z;
    }
}

I like it very much but now I have the following problem: how do I test subAlg01 and subAlg02 using JUnit?

By the way: I'm using eclipse.

Thanks for you help.

Edit: I try to explain better: I have, let's say, a sorting algorithm and I want to test it to be sure it runs as expected. This sorting algorithms is used by only method m of class X. I could make it a private method of class X but class X usually has nothing to do with sorting, so why "spoil" class X with the sorting method? So I put it inside method m. Some time later I want to improve my sorting algorithm (I make it faster) but I want to be sure that it's behavior is as expected, so I want to re-test it with the original tests.

That's what I want to do, maybe there is no solution, I hope someone may help me.

Edit after answer choice. I selected Rodney answer because his solution is the one I adopted: a standalone helper class helps me (it's a helper!) to have a clear view of what are the sub methods and it also gives me the ability to test them.

+6  A: 

You should only test the public interface of classes, not private members or private inner classes. Private members are meant to be implementation details, used only by public methods of the class (directly or indirectly). So you can unit test these indirectly via their caller methods. If you feel you don't have enough granularity in those unit tests, or that you can't sense (some of) the results you are interested in, this probably signs a problem with your design: the class may be too big, trying to do too much, thus some of its functionality may need to be extracted into a separate class, where it can then be unit tested directly.

In the current example, if the inner class itself contains a lot of code, you may simply turn it into a top-level class, then you can unit test its methods directly.

(Btw your inner class should be static if it doesn't need to refer to the enclosing class instance.)

Péter Török
Hi, thank for the reply. I have already read many answers like your, but it's not very clear to me the meaning. Please can you help me understand better? I have a piece of code which is used only once, but I need to verify if it does what it's expected to do. Ho do I accomplish that? Testing seemed to me a good choice.
Filippo Tabusso
@Filippo, see my update. Testing is indeed a good choice - write tests that cover all the different usage scenarios you can come up with. A code coverage tool helps you spot untested code parts.
Péter Török
@Péter about your suggestion on static: inner classes may be static local inner class no
Filippo Tabusso
@Péter I can't put the static modifier in a local-inner-class (i.e. inside a method)
Filippo Tabusso
Local classes are quite different from inner classes, so you can't declare them static. Local classes are like anonymous classes, except that they have a name which you can use multiple times inside the method. http://docstore.mik.ua/orelly/java-ent/jnut/ch03_11.htm
Esko Luontola
@Péter if I turn the inner class into a top level class I have created a new class just for testing. Is it worthwhile? (remember I didn't like having private methods, so I don't want to have an extra class!)
Filippo Tabusso
@Filippo, oops, I didn't notice that was a local class instead of an inner class - my bad :-(
Péter Török
@Filippo, testability (or the lack thereof) is one of the most important properties of a design. A design which can't be unit tested properly, is not a good design (usually - there are exceptions as always, but these are rare). Of course it is up to you how you define "properly" :-) I tried to give good rules of thumb in my answer. In OOP it is desirable to have many smaller classes instead of a few big ones, but again, "small" and "big" is relative.
Péter Török
Exactly, as Peter saied, the problem is that if you have a submethod that shorts something, you should extract it to other class.Remember, all the classes should have one and only one defined purpose.And thanks to the test is that you are realizing that you have a class that does two different things.
Pau
+1  A: 

You cannot reach these classes from the outside, so junit cannot test Them. You must have things public to test Them.

Thorbjørn Ravn Andersen
This is not correct. Mock frameworks such as JMockit can handle private inner classes (as well as private methods and members) just fine.
jchilders
JMockit most likely does naughty things with reflection then, which junit doesn't.
Thorbjørn Ravn Andersen
Do you know if JMockit (or similar frameworks) can test methods within local inner classes?
Filippo Tabusso
A: 

You should avoid over complicating your code just because you

don't like having a proliferation of methods

In your case you can test the methods if they are methods of the outer class or if you absolutely need the inner class then place it outside the mainAlg() method so it is visible globally.

public class NewStyle {

    public int mainAlg() {

        Nested n = new Nested();
        int x = n.subAlg01();
        int y = n.subAlg02();

        int z = x * y;
        return z;
    }

    class Nested {

        public int subAlg01() {
            return 3;

        }

        public int subAlg02() {
            return 5;
        }
    }
}

this can then be called using new NewStyle().new Nested().subAlg01();

Kingo
Thank for the reply. I also tried this solution but I like it less than mine since, looking at the class, I still don't have a clear view that the subAlgs are only part of the main algorithm and are not used by anyone else. Nevertheless it allows testing.
Filippo Tabusso
new NewStyle().new Nested().subAlg01(); Are you sure? I've NEVER seen this... /ponder
Chris Kaminski
A: 

Hm, I know that languages like Groovy are often used to do unit testing on Java, and are able to access private fields and methods transparently.....but I'm not sure about nested classes. I can understand why you might want to do this sort of thing, but I kind of take the same position I take with testing getters and setters, they should be tested as a side effect of testing your public methods, and if they don't get tested that way, then why are they there to begin with?

mezmo
+1  A: 

Filippo, I understand your frustration with the problem and with some of the answers. When I first started using JUnit many years ago, I too wanted to test private code, and I thought it silly of the gurus to say it was a bad idea.

Turns out they were right (surprise!) but only after writing quite a few tests did I understand why. You might need to go through the same process, but you will eventually come to the same conclusion ;-)

Anyway, in your situation, I would make Nested into a proper standalone class, possibly in a separate package to make obvious that it's a helper classes. Then I would write tests for it directly, independent of any other tests.

Then I'd write tests for NewStyle and focus only on the behaviour of NewStyle.

(Quite probably I would also inject Nested into NewStyle rather than instantiating it within NewStyle -- i.e. make it an argument to NewStyle's constructor.

Then when I write tests for NewStyle in the test I'd pass in an instance of Nested and carry on. If I felt particularly tricky, I'd create an interface out of Nested and create a second implementation, and test NewStyle with that, too.)

Rodney Gitzel
+1 because your solution is the same I have currently adopted (standalone helper class)
Filippo Tabusso