Haifeng Zhang
Haifeng Zhang

Reputation: 31895

How can we test package-private class?

I am reading book Effective Java, in Item 13: Minimize the accessibility of classes and members, it mentioned that:

To facilitate testing, you may be tempted to make a class, interface, or member more accessible. This is fine up to a point. it is acceptable to make a private member of a public class package-private in order to test it, but it is not acceptable to raise the accessibility any higher than that. In other words, it is not acceptable to make a class, interface, or member a part of packages's exported API to facilitate testing.

I know we should encapsulate members, hiding information from clients, we can test them by accessing the class with setters and getters, but How should I understand make class package-private accessible, if so How to test it?

Upvotes: 28

Views: 15011

Answers (3)

martin
martin

Reputation: 1328

If you want to hide details (that are required for your tests) of your class, you could use lombok to easily generate an appropriate getter-Method with package-level access, which would allow reading (from test classes in same package) but prevent mutation (everywhere) of a certain field.

public class SimpleRetryStrategy implements RetryStrategy {
    @Getter(AccessLevel.PACKAGE)
    private final int maxRetries;

Upvotes: 0

Michael Gantman
Michael Gantman

Reputation: 7792

Basically it means that your tester class should reside in the same package as your tested class. That would make your tested class and all package protected members and methods accessible to your testing class. The classes may be located under different roots: your tested class may be under src/main/java/myrootpackage/first/second/MyClass.java and your testing class may be located under src/test/java/myrootpackage/first/second/MyClassTester.java.

Upvotes: 28

Michael Lihs
Michael Lihs

Reputation: 8220

I guess what the author means is that instead of

package my.package;

class TestableClass {
     private String property;
}

You can change the visibility to

package my.package;

class TestableClass {
    String property;
}

With the second implementation you can access the property from a test in the package my.package like

package my.package;

class TestableClassTest {
    // ...
}

At the same time, a subclass cannot access the property - that's the benefit comapred to protected.

Upvotes: 5

Related Questions