How do I test a class that has private methods, fields or inner classes?

Asked 2023-09-20 20:19:43 View 940,740

How do I use JUnit to test a class that has internal private methods, fields or nested classes?

It seems bad to change the access modifier for a method just to be able to run a test.

  • Best way to test a private method is not testing it directly - anyone
  • Check the article Testing Private Methods with JUnit and SuiteRunner. - anyone
  • why should test a private function ? It will automatically be tested anyway (and must be tested) when you test the feature/method which is using it the private function. - anyone
  • I've rolled this question back to its original state, prior to generifying the question. In its current state, the answers are highly Java-oriented, and the question was largely focused on the "how", meaning that the later versions erasing Java and generalizing for other languages, and at the end flipping the focus to C++ invalidates far too many of the answers. A generalized form asking "how to" in any arbitrary language and framework would also be considered far too broad, meaning the last few edits pushed this question towards being closed rather than being constructive. - anyone
  • @AkashVerma: For the same reason you want to do unit tests instead of just a system test? - anyone

Answers

If you have somewhat of a legacy Java application, and you're not allowed to change the visibility of your methods, the best way to test private methods is to use reflection.

Internally we're using helpers to get/set private and private static variables as well as invoke private and private static methods. The following patterns will let you do pretty much anything related to the private methods and fields. Of course, you can't change private static final variables through reflection.

Method method = TargetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

And for fields:

Field field = TargetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);

Notes:

  1. TargetClass.getDeclaredMethod(methodName, argClasses) lets you look into private methods. The same thing applies for getDeclaredField.
  2. The setAccessible(true) is required to play around with privates.

Answered   2023-09-20 20:19:43

  • Useful if you don't know the API perhaps, but if you are having to test private methods in this manner there is something up with your design. As another poster says unit testing should test the class's contract: if the contract is too broad and instantiates too much of the system then the design should be addressed. - anyone
  • We develop methods that do a single specific task that allow the class to perform its specific task. These methods should not be public and still need to be tested independently. So yes reflection is a good way to do this and no your design does not need review if you are using reflection for this purpose. - anyone

The best way to test a private method is via another public method. If this cannot be done, then one of the following conditions is true:

  1. The private method is dead code
  2. There is a design smell near the class that you are testing
  3. The method that you are trying to test should not be private

Answered   2023-09-20 20:19:43

  • Further, we never get close to 100% code coverage anyway, so why not focus your time doing quality testing on the methods that clients will actually be using directly. - anyone
  • @grinch Spot on. The only thing you would gain from testing private methods is debugging information, and that's what debuggers are for. If your tests of the class's contract have full coverage then you have all the information you need. Private methods are an implementation detail. If you test them you will have to change your tests every time your implementation changes, even if the contract doesn't. In the full life cycle of the software this is likely to cost a lot more than the benefit it gives. - anyone
  • I am impressed how often the "should not be private" claim is repeated across the answers here, as if "make it public so you can test it" could not easily lead to code-smell that invites others to abuse parts of a class. Exposing sensible internals just for easier testing of various code paths isn't always sensible, so don't follow this device here blindly! - anyone
  • The "should not be private" here doesn't say "just make it public for test". If there is a need for testing the private method, there must be something like the three conditions he mentioned here. If you want 100% test coverage, that's still possible by calling the public methods of the class with various parameters, except when it is unused or contains dead code, eg. if (x == null) which is never reached because you nullchecked in the public method already. But then you should cleanup the private method, instead of inventing test cases that cannot happen. - anyone
  • A counterexample (real) situation where none of these 3 points is valid (as far as I can think): A public method foo() will 1. use a private method bar() and 2. run in an infinite loop. As far as I know you can't test bar() by calling foo() otherwise the test case will run forever. - anyone

When I have private methods in a class that are sufficiently complicated that I feel the need to test the private methods directly, that is a code smell: my class is too complicated.

My usual approach to addressing such issues is to tease out a new class that contains the interesting bits. Often, this method and the fields it interacts with, and maybe another method or two can be extracted in to a new class.

The new class exposes these methods as 'public', so they're accessible for unit testing. The new and old classes are now both simpler than the original class, which is great for me (I need to keep things simple, or I get lost!).

Note that I'm not suggesting that people create classes without using their brain! The point here is to use the forces of unit testing to help you find good new classes.

Answered   2023-09-20 20:19:43

  • Why create a new class when you can make your method public anyway? - anyone
  • If you have a mix of private and public methods on a class, that's a hint that multiple responsibilities are present. - anyone
  • Use reflection to access the private method in a test. For example, i have an implementation of an algorithm in a private method and this method is used in another public method. So i need to test this algorithm properly (even while i am writing this algorithm). So why do i need to do a hack in the productive code only to be able to test this method? Yes, using java reflection is also a hack, but only in the test. And if i decide to move the method (for some other reason) in to a utils class, i can just move the test too .. done. Easy peasy, readable, maintainable. - anyone

I have used reflection to do this for Java in the past, and in my opinion it was a big mistake.

Strictly speaking, you should not be writing unit tests that directly test private methods. What you should be testing is the public contract that the class has with other objects; you should never directly test an object's internals. If another developer wants to make a small internal change to the class, which doesn't affect the classes public contract, he/she then has to modify your reflection based test to ensure that it works. If you do this repeatedly throughout a project, unit tests then stop being a useful measurement of code health, and start to become a hindrance to development, and an annoyance to the development team.

What I recommend doing instead is using a code coverage tool, such as Cobertura, to ensure that the unit tests you write provide decent coverage of the code in private methods. That way, you indirectly test what the private methods are doing, and maintain a higher level of agility.

Answered   2023-09-20 20:19:43

  • +1 to this. In my opinion it's the best answer to the question. By testing private methods you are testing the implementation. This defeats the purpose of unit testing, which is to test the inputs/outputs of a class' contract. A test should only know enough about the implementation to mock the methods it calls on its dependencies. Nothing more. If you can not change your implementation without having to change a test - chances are that your test strategy is poor. - anyone
  • @Colin M That's not really what he's asking though ;) Let him decide it, you don't know the project. - anyone
  • Not really true. It could take a lot of effort to test a small part of the private method through the public method using it. The public method could require significant setup before you reach the line that calls your private method - anyone
  • I agree. You should test, if the contract is fulfilled. You should not test, how this is done. If the contact is fulfilled without reaching 100% code coverage (in private methods), that might be dead or useless code. - anyone
  • non-trivial private methods are a code smell and indicate a need to refactor code into appropriate public methods/services. - anyone

From this article: Testing Private Methods with JUnit and SuiteRunner (Bill Venners), you basically have 4 options:

  1. Don't test private methods.
  2. Give the methods package access.
  3. Use a nested test class.
  4. Use reflection.

Answered   2023-09-20 20:19:43

  • 5th option, like mentioned above is testing the public method that calls the private method? Correct? - anyone
  • @LorenzoLerate I've been wrestling with this because I'm doing embedded development and I'd like my software to be as small as possible. Size constraints and performance is the only reason I can think of. - anyone
  • I really like the test using reflection: Here the pattern Method method = targetClass.getDeclaredMethod(methodName, argClasses); method.setAccessible(true); return method.invoke(targetObject, argObjects); - anyone
  • @user2441441 that's the same as #1 — don't test private methods - anyone

Generally a unit test is intended to exercise the public interface of a class or unit. Therefore, private methods are implementation detail that you would not expect to test explicitly.

Answered   2023-09-20 20:19:43

  • That's the best answer IMO, or as it is usually said, test behaviour, not methods. Unit testing is not a replacement for source code metrics, static code analysis tools and code reviews. If private methods are so complex that they need separates tests then it probably needs to be refactored, not more tests thrown at it. - anyone
  • so don't write private methods, just create 10 other small classes ? - anyone
  • No, it basically means that you can test the functionality of the private methods using the public method that invokes them. - anyone
  • @AkshatSharda correct - and morever, if you can't test some part of the private method through the public API then you probably don't need that functionality in the private method. I've found that a side effect of the "test through the API" methodology is that you write less dead code. - anyone
  • I don't agree. If I want to be sure of my code, I would like to test every piece that the code flow goes through. Unit can be even private methods that implement self-contained logic. - anyone

Just two examples of where I would want to test a private method:

  1. Decryption routines - I would not want to make them visible to anyone to see just for the sake of testing, else anyone can use them to decrypt. But they are intrinsic to the code, complicated, and need to always work (the obvious exception is reflection which can be used to view even private methods in most cases, when SecurityManager is not configured to prevent this).

  2. Creating an SDK for community consumption. Here public takes on a wholly different meaning, since this is code that the whole world may see (not just internal to my application). I put code into private methods if I don't want the SDK users to see it - I don't see this as code smell, merely as how SDK programming works. But of course I still need to test my private methods, and they are where the functionality of my SDK actually lives.

I understand the idea of only testing the "contract". But I don't see one can advocate actually not testing code—your mileage may vary.

So my trade-off involves complicating the JUnit tests with reflection, rather than compromising my security and SDK.

Answered   2023-09-20 20:19:43

  • While you should never make a method public just to test it, private is not the only alternative. No access modifier is package private and means that you can unit test it as long as your unit test lives in the same package. - anyone
  • I was commenting on your answer, point 1 in particular, not the OP. There is no need to make a method private just because you don't want it to be public. - anyone
  • @ngreen true thx - I was lazy with the word "public". I have updated the answer to include public, protected, default (and to make mention of reflection). The point I was trying to make is that there is good reason for some code to be secret, however that shouldn't prevent us from testing it. - anyone
  • Thanks for giving real examples to everyone. Most answers are good, but in a theorical point of view. In real world, we do need to hide implementation from the contract, and we still need to test it. Reading all these, I think maybe this should be a whole new level of testing, with a different name - anyone
  • One more example - Crawler HTML parsers. Having to parse a whole html page into domain objects requires a ton of nitty-gritty logic of validating little parts of the structure. It makes sense to break that up into methods and call it from one public method, yet it doesn't make sense to have all the smaller methods composing it be public, nor does it make much sense to create 10 classes per HTML page. - anyone

The private methods are called by a public method, so the inputs to your public methods should also test private methods that are called by those public methods. When a public method fails, then that could be a failure in the private method.

Answered   2023-09-20 20:19:43

  • True fact. The problem is when the implementation is more complicated, like if one public method calls several private methods. Which one did fail? Or if it is a complicated private method, that can't be exposed nor transferred to a new class - anyone
  • You already mentioned why the private method should be tested. You said "then that could be ", so you are not sure. IMO, whether a method should be tested is orthogonal to its access level. - anyone

In the Spring Framework you can test private methods using this method:

ReflectionTestUtils.invokeMethod()

For example:

ReflectionTestUtils.invokeMethod(TestClazz, "createTest", "input data");

Answered   2023-09-20 20:19:43

  • The cleanest and the most concise solution so far, but only if you are using Spring. - anyone

Another approach I have used is to change a private method to package private or protected then complement it with the @VisibleForTesting annotation of the Google Guava library.

This will tell anybody using this method to take caution and not access it directly even in a package. Also a test class need not be in same package physically, but in the same package under the test folder.

For example, if a method to be tested is in src/main/java/mypackage/MyClass.java then your test call should be placed in src/test/java/mypackage/MyClassTest.java. That way, you got access to the test method in your test class.

Answered   2023-09-20 20:19:43

  • I didn't know about this one, it's interresting, I still think that if you need that kind of annottaion you have design issues. - anyone
  • To me, this is like saying instead of giving a one-off key to your fire warden to test the fire drill, you leave your front door unlocked with a sign on the door saying - "unlocked for testing - if you're not from our company, please don't enter". - anyone
  • @FrJeremyKrieg - what does that mean ? - anyone
  • @MasterJoe2: the purpose of a fire test is to improve the safety of your building against the risk of fire. But you have to give the warden access to your building. If you permanently leave the front door unlocked, you increase the risk of unauthorised access and make it less safe. The same is true of the VisibleForTesting pattern - you're increasing the risk of unauthorised access in order to reduce the risk of "fire". Better to grant access as a one-off for testing only when you need to (eg, using reflection) rather than leave it permanently unlocked (non-private). - anyone
  • @FrJeremyKrieg leaving your door unlocked would be equivalent to making your private method public just for testing. I'm assuming you know package-private means only classes in the same package have access. Making it package-private is more like giving your garage door code to your neighbors and the fire warden only. Is it less secure than a private method? Sure. Slightly. Question: How would you grant access as a one-off through reflection? Access to private methods is available to anyone through reflection. IMHO using reflection is not any better than package-private access. - anyone

To test legacy code with large and quirky classes, it is often very helpful to be able to test the one private (or public) method I'm writing right now.

I use the junitx.util.PrivateAccessor-package for Java. It has lots of helpful one-liners for accessing private methods and private fields.

import junitx.util.PrivateAccessor;

PrivateAccessor.setField(myObjectReference, "myCrucialButHardToReachPrivateField", myNewValue);
PrivateAccessor.invoke(myObjectReference, "privateMethodName", java.lang.Class[] parameterTypes, java.lang.Object[] args);

Answered   2023-09-20 20:19:43

  • Be sure to download the entire JUnit-addons (sourceforge.net/projects/junit-addons) package, not the Source Forge-Recommended Project PrivateAccessor. - anyone
  • And be sure that, when you're using a Class as your first parameter in these methods, that you're accessing only static members. - anyone

Having tried Cem Catikkas' solution using reflection for Java, I'd have to say his was a more elegant solution than I have described here. However, if you're looking for an alternative to using reflection, and have access to the source you're testing, this will still be an option.

There is possible merit in testing private methods of a class, particularly with test-driven development, where you would like to design small tests before you write any code.

Creating a test with access to private members and methods can test areas of code which are difficult to target specifically with access only to public methods. If a public method has several steps involved, it can consist of several private methods, which can then be tested individually.

Advantages:

  • Can test to a finer granularity

Disadvantages:

  • Test code must reside in the same file as source code, which can be more difficult to maintain
  • Similarly with .class output files, they must remain within the same package as declared in source code

However, if continuous testing requires this method, it may be a signal that the private methods should be extracted, which could be tested in the traditional, public way.

Here is a convoluted example of how this would work:

// Import statements and package declarations

public class ClassToTest
{
    private int decrement(int toDecrement) {
        toDecrement--;
        return toDecrement;
    }

    // Constructor and the rest of the class

    public static class StaticInnerTest extends TestCase
    {
        public StaticInnerTest(){
            super();
        }

        public void testDecrement(){
            int number = 10;
            ClassToTest toTest= new ClassToTest();
            int decremented = toTest.decrement(number);
            assertEquals(9, decremented);
        }

        public static void main(String[] args) {
            junit.textui.TestRunner.run(StaticInnerTest.class);
        }
    }
}

The inner class would be compiled to ClassToTest$StaticInnerTest.

See also: Java Tip 106: Static inner classes for fun and profit

Answered   2023-09-20 20:19:43

If using Spring, ReflectionTestUtils provides some handy tools that help out here with minimal effort. For example, to set up a mock on a private member without being forced to add an undesirable public setter:

ReflectionTestUtils.setField(theClass, "theUnsettableField", theMockObject);

Answered   2023-09-20 20:19:43

As others have said... don't test private methods directly. Here are a few thoughts:

  1. Keep all methods small and focused (easy to test, easy to find what is wrong)
  2. Use code coverage tools. I like Cobertura (oh happy day, it looks like a new version is out!)

Run the code coverage on the unit tests. If you see that methods are not fully tested add to the tests to get the coverage up. Aim for 100% code coverage, but realize that you probably won't get it.

Answered   2023-09-20 20:19:43

  • Up for code coverage. No matter what kind of logic is in the private method, you are still invoking those logic through a public method. A code coverage tool can show you which parts are covered by the test, therefore you can see if your private method is tested. - anyone
  • I have seen classes where the only public method is main[], and they pop up GUI plus connect the database and a couple of web servers worldwide. Easy to say "do not test indirectly"... - anyone

Private methods are consumed by public ones. Otherwise, they're dead code. That's why you test the public method, asserting the expected results of the public method and thereby, the private methods it consumes.

Testing private methods should be tested by debugging before running your unit tests on public methods.

They may also be debugged using test-driven development, debugging your unit tests until all your assertions are met.

I personally believe it is better to create classes using TDD; creating the public method stubs, then generating unit tests with all the assertions defined in advance, so the expected outcome of the method is determined before you code it. This way, you don't go down the wrong path of making the unit test assertions fit the results. Your class is then robust and meets requirements when all your unit tests pass.

Answered   2023-09-20 20:19:43

  • Although this is true, it can lead to some very complicated tests--it's a better pattern to test a single method at a time (Unit testing) rather than a whole group of them. Not a terrible suggestion but I think there are better answers here--this should be a last resort. - anyone

If you're trying to test existing code that you're reluctant or unable to change, reflection is a good choice.

If the class's design is still flexible, and you've got a complicated private method that you'd like to test separately, I suggest you pull it out into a separate class and test that class separately. This doesn't have to change the public interface of the original class; it can internally create an instance of the helper class and call the helper method.

If you want to test difficult error conditions coming from the helper method, you can go a step further. Extract an interface from the helper class, add a public getter and setter to the original class to inject the helper class (used through its interface), and then inject a mock version of the helper class into the original class to test how the original class responds to exceptions from the helper. This approach is also helpful if you want to test the original class without also testing the helper class.

Answered   2023-09-20 20:19:43

Testing private methods breaks the encapsulation of your class because every time you change the internal implementation you break client code (in this case, the tests).

So don't test private methods.

Answered   2023-09-20 20:19:43

  • unit test and src code are a pair. If you change the src, maybe you have to change the unit test. That is the sense of junit test. They shall garuantee that all works as before. and it is fine if they break, if you change the code. - anyone
  • Do not agree that unit test should change if code changes. If you are ordered to add functionality to a class without changing the existing functionality of the class, then the exist unit tests ought to pass even after you've changed your code. As Peter mentions, unit tests ought to test the interface, not how it is done internally. In Test Driven Development unit tests are created before the code is written, to focus on the interface of the class, not on how it is solved internally. - anyone

The answer from JUnit.org FAQ page:

But if you must...

If you are using JDK 1.3 or higher, you can use reflection to subvert the access control mechanism with the aid of the PrivilegedAccessor. For details on how to use it, read this article.

If you are using JDK 1.6 or higher and you annotate your tests with @Test, you can use Dp4j to inject reflection in your test methods. For details on how to use it, see this test script.

P.S. I'm the main contributor to Dp4j. Ask me if you need help. :)

Answered   2023-09-20 20:19:43

If you want to test private methods of a legacy application where you can't change the code, one option for Java is jMockit, which will allow you to create mocks to an object even when they're private to the class.

Answered   2023-09-20 20:19:43

  • As part of the jmockit library, you have access to the Deencapsulation class which makes testing private methods easy: Deencapsulation.invoke(instance, "privateMethod", param1, param2); - anyone
  • I use this approach all the time. Very helpful - anyone

PowerMockito is made for this.

Use a Maven dependency:

    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-core</artifactId>
        <version>2.0.7</version>
        <scope>test</scope>
    </dependency>

Then you can do

import org.powermock.reflect.Whitebox;
...
MyClass sut = new MyClass();
SomeType rval = Whitebox.invokeMethod(sut, "myPrivateMethod", params, moreParams);

Answered   2023-09-20 20:19:43

I tend not to test private methods. There lies madness. Personally, I believe you should only test your publicly exposed interfaces (and that includes protected and internal methods).

Answered   2023-09-20 20:19:43

If you're using JUnit, have a look at junit-addons. It has the ability to ignore the Java security model and access private methods and attributes.

Answered   2023-09-20 20:19:43

I would suggest you refactoring your code a little bit. When you have to start thinking about using reflection or other kind of stuff, for just testing your code, something is going wrong with your code.

You mentioned different types of problems. Let's start with private fields. In case of private fields I would have added a new constructor and injected fields into that. Instead of this:

public class ClassToTest {

    private final String first = "first";
    private final List<String> second = new ArrayList<>();
    ...
}

I'd have used this:

public class ClassToTest {

    private final String first;
    private final List<String> second;

    public ClassToTest() {
        this("first", new ArrayList<>());
    }

    public ClassToTest(final String first, final List<String> second) {
        this.first = first;
        this.second = second;
    }
    ...
}

This won't be a problem even with some legacy code. Old code will be using an empty constructor, and if you ask me, refactored code will look cleaner, and you'll be able to inject necessary values in test without reflection.

Now about private methods. In my personal experience when you have to stub a private method for testing, then that method has nothing to do in that class. A common pattern, in that case, would be to wrap it within an interface, like Callable and then you pass in that interface also in the constructor (with that multiple constructor trick):

public ClassToTest() {
    this(...);
}

public ClassToTest(final Callable<T> privateMethodLogic) {
    this.privateMethodLogic = privateMethodLogic;
}

Mostly all that I wrote looks like it's a dependency injection pattern. In my personal experience it's really useful while testing, and I think that this kind of code is cleaner and will be easier to maintain. I'd say the same about nested classes. If a nested class contains heavy logic it would be better if you'd moved it as a package private class and have injected it into a class needing it.

There are also several other design patterns which I have used while refactoring and maintaining legacy code, but it all depends on cases of your code to test. Using reflection mostly is not a problem, but when you have an enterprise application which is heavily tested and tests are run before every deployment everything gets really slow (it's just annoying and I don't like that kind of stuff).

There is also setter injection, but I wouldn't recommended using it. I'd better stick with a constructor and initialize everything when it's really necessary, leaving the possibility for injecting necessary dependencies.

Answered   2023-09-20 20:19:43

  • Disagree with the ClassToTest(Callable) injection. That makes ClassToTest more complicated. Keep it simple. Also, that then requires someone else to tell ClassToTest something that ClassToTest should be the boss of. There is a place for injecting logic, but this is not it. You have just made the class harder to maintain, not easier. - anyone
  • Also, it is preferable if your method of testing X does not increase X complexity to the point where it might cause more problems... and therefore require additional testing... which if you've implemented in a way that can cause more problems... (this is not an infinite loops; each iteration is likely smaller than the one before it, but still annoying) - anyone
  • Could you explain why would it make class ClassToTest harder to maintain? Actually it makes your application easier to maintain, what do you suggest making new class for every different value you'll need in first and 'second' variables? - anyone
  • Method of testing doesn't increase complexity. It's just your class which is poorly written, so poorly that it can't be tested. - anyone
  • Actually, on third (or fourth?) read over, I see I may have missed a point. In your no-arg public ClassToTest() { this(...); }, is that implying that the class no-arg constructor is generally used, that it can supply its own logic known internally to the class, and the other constructor used only for testing (or if B wants to change its behavior for some reason; a handy side effect)? I did not catch that the first couple reads over. - anyone

Here is my generic function to test private fields:

protected <F> F getPrivateField(String fieldName, Object obj)
    throws NoSuchFieldException, IllegalAccessException {
    Field field =
        obj.getClass().getDeclaredField(fieldName);

    field.setAccessible(true);
    return (F)field.get(obj);
}

Answered   2023-09-20 20:19:43

Please see below for an example;

The following import statement should be added:

import org.powermock.reflect.Whitebox;

Now you can directly pass the object which has the private method, method name to be called, and additional parameters as below.

Whitebox.invokeMethod(obj, "privateMethod", "param1");

Answered   2023-09-20 20:19:43

A private method is only to be accessed within the same class. So there is no way to test a “private” method of a target class from any test class. A way out is that you can perform unit testing manually or can change your method from “private” to “protected”.

And then a protected method can only be accessed within the same package where the class is defined. So, testing a protected method of a target class means we need to define your test class in the same package as the target class.

If all the above does not suits your requirement, use the reflection way to access the private method.

Answered   2023-09-20 20:19:43

  • You're mixing "protected" with "friendly." A protected method can only be accessed by a class whose objects are assignable to the target class (i.e subclasses). - anyone
  • Actually there is no "Friendly" in Java, the term is "Package" and it's indicated by the lack of a private/public/protected modifier. I would have just corrected this answer but there is a really good one that already says this--so I'd just recommend deleting it. - anyone
  • I almost downvoted, thinking all along "This answer is just plain wrong." until I got to the very last sentence, which contradicts the rest of the answer. The last sentence should have been the first. - anyone

As many above have suggested, a good way is to test them via your public interfaces.

If you do this, it's a good idea to use a code coverage tool (like EMMA) to see if your private methods are in fact being executed from your tests.

Answered   2023-09-20 20:19:43

  • You should not indirectly test! Not only touching via coverage ; test that the expected result is delivered! - anyone

Today, I pushed a Java library to help testing private methods and fields. It has been designed with Android in mind, but it can really be used for any Java project.

If you got some code with private methods or fields or constructors, you can use BoundBox. It does exactly what you are looking for. Here below is an example of a test that accesses two private fields of an Android activity to test it:

@UiThreadTest
public void testCompute() {

    // Given
    boundBoxOfMainActivity = new BoundBoxOfMainActivity(getActivity());

    // When
    boundBoxOfMainActivity.boundBox_getButtonMain().performClick();

    // Then
    assertEquals("42", boundBoxOfMainActivity.boundBox_getTextViewMain().getText());
}

BoundBox makes it easy to test private/protected fields, methods and constructors. You can even access stuff that is hidden by inheritance. Indeed, BoundBox breaks encapsulation. It will give you access to all that through reflection, but everything is checked at compile time.

It is ideal for testing some legacy code. Use it carefully. ;)

Answered   2023-09-20 20:19:43

First, I'll throw this question out: Why do your private members need isolated testing? Are they that complex, providing such complicated behaviors as to require testing apart from the public surface? It's unit testing, not 'line-of-code' testing. Don't sweat the small stuff.

If they are that big, big enough that these private members are each a 'unit' large in complexity—consider refactoring such private members out of this class.

If refactoring is inappropriate or infeasible, can you use the strategy pattern to replace access to these private member functions / member classes when under unit test? Under unit test, the strategy would provide added validation, but in release builds it would be simple passthrough.

Answered   2023-09-20 20:19:43

  • Because often a particular piece of code from a public method is refactored into an internal private method and is really the critical piece of logic which you might have got wrong. You want to test this independently from the public method - anyone
  • Even the shortest code sometimes without unit test is not correct. Just try to caluclate the difference between 2 geograhpical angles. 4 lines of code, and most will not do it correct at first try. Such methods needs unit test, because the form the base of a trustfull code. (Ans such usefull code can be public, too; less usefull protected - anyone

I recently had this problem and wrote a little tool, called Picklock, that avoids the problems of explicitly using the Java reflection API, two examples:

Calling methods, e.g. private void method(String s) - by Java reflection

Method method = targetClass.getDeclaredMethod("method", String.class);
method.setAccessible(true);
return method.invoke(targetObject, "mystring");

Calling methods, e.g. private void method(String s) - by Picklock

interface Accessible {
  void method(String s);
}

...
Accessible a = ObjectAccess.unlock(targetObject).features(Accessible.class);
a.method("mystring");

Setting fields, e.g. private BigInteger amount; - by Java reflection

Field field = targetClass.getDeclaredField("amount");
field.setAccessible(true);
field.set(object, BigInteger.valueOf(42));

Setting fields, e.g. private BigInteger amount; - by Picklock

interface Accessible {
  void setAmount(BigInteger amount);
}

...
Accessible a = ObjectAccess.unlock(targetObject).features(Accessible.class);
a.setAmount(BigInteger.valueOf(42));

Answered   2023-09-20 20:19:43