Kevin
Kevin

Reputation: 6292

How to unit test a private functionality

I have a question regarding unit testing.

I have a function which does the following thing:

void myFunction(List<MyClass> myList) {

// 1. Sort the list
// 2. Post Process the list

}

Now I want to test this function. But the problem is I should not test these two things at the same time. I am therefore thinking to extract the "Post Process the list" part as a separate function.

But the problem is the task of "Post Process the list" is only used by myFunction and I want to make it private to the class.

If I make it private I won't be able to test it from outside.

What is the general rule of this kind of scenario? Must I change a private function to public only for testing?

Or if there are any other patterns I should use?

Many thanks

Upvotes: 2

Views: 319

Answers (7)

TGH
TGH

Reputation: 39248

I typically consider private methods to be part of the method under test. They typically consist of code that has been moved out of the original method to make it leaner and shorter, and more modular. However from a test perspective you would be testing the same code if you moved the content of the private method into your method under test.

The question of trying to isolate the return values of private methods to simulate various conditions is is often valid though. I think its' part of the larger question of how to write testable code.

One approach with very little overhead is to rely on basic overriding of methods. You can make your private methods protected virtual instead, and override them in your test: Here's an example of that too :
http://www.unit-testing.net/CurrentArticle/How-To-Remove-Data-Dependencies-In-Unit-Tests.html The example is C#, but the concept applies to all object oriented languages

Upvotes: 0

Balaswamy Vaddeman
Balaswamy Vaddeman

Reputation: 8530

Below things you may consider for testing a private method.

1.create public method written only for the purpose of testing. (or)

2.create nested class for testing (or)

3.use reflection to test it.

useful link,another useful link from stackoverflow

Upvotes: 0

Rangi Lin
Rangi Lin

Reputation: 9451

It depends.

Dose the sub routine contains common behavior that you should extract ?

Take your first sub routine as example. If you're not sorting your list by Comparator<T>, you should refactor it, then test that Comprartor<T> class instead of your private method. If Post process are actually some algorithm or common business logic, you might want to refactor it using Strategy pattern then test those class you just extract.

The point is, if a private method is complex enough to require a unit-test, then chance is probably you should not put them there, otherwise you should just test through it's public API.

It's a legacy system, and it will take forever to refactor that method.

check Bad Smells in Code : Long method for long method refactor, Method Object is a good strategy for things like this.

It's fine, I just want to test them.

Then you can test through Java reflection API, and I believe there are some mocking framework like PowerMock can also help you.

Upvotes: 0

Peter Lawrey
Peter Lawrey

Reputation: 533492

The test method only needs to be package-local.

You can call private methods using reflections and there are mocking libraries which allow you to test private methods. But I would just make it package-local as it shows the method is access from elsewhere in the package (which it is either way)

Upvotes: 3

Jesper
Jesper

Reputation: 206796

As others have said, you don't need to make the method public, just package visible.

Google Guava has a @VisibleForTesting annotation which is meant for situations like this. You put this annotation on a method, just to document that the reason that the method isn't private is only for testing. The annotation doesn't do anything, it's just meant as a warning for programmers that they shouldn't call it from outside the class. (Some static code checking tool could in principle check if methods with this annotation aren't called from anywhere except inside the class or from test code).

Ofcourse it's kind of ugly to have to modify your code to do this just for testing. If you want to avoid this, you can do tricks with reflection to call the private method:

public class Sandbox {
    public static void main(String[] args) throws Exception {
        Example e = new Example();

        Method m = Example.class.getDeclaredMethod("myFunction", List.class);
        m.setAccessible(true);
        m.invoke(e, Arrays.asList("one", "two", "three"));
    }
}

class Example {
    private void myFunction(List<String> data) {
        System.out.println("Hey, what are you doing! " + data);
    }
}

Upvotes: 2

matt freake
matt freake

Reputation: 5090

Another vote for package-local. Just ensure that your newly exposed method is clearly named and documented so that in future it is not called inappropriately.

Upvotes: 0

Esko Luontola
Esko Luontola

Reputation: 73625

In general, you should always test the functionality through public methods. If there is some functionality in private methods, which cannot otherwise be tested well enough, that's an indication that the method has a responsibility which should be moved to its own class (this also helps to achieve high cohesion). Then that newly extracted class can be tested directly though its public methods.

Upvotes: 0

Related Questions