New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Jmockit 1.27: Faking private method not possible #324
Comments
Yes, this was a change in version 1.27. More info in the release notes. |
We have chosen the jmockit lib among others because of the possibility to mock private methods. |
Mocking of private methods in expectation blocks was dropped in version 1.23 - see release note. |
Can you help me to understand intended support for mocking private methods internal to the codebase going forward? Consider the following class: public class Validator{
public static boolean isValid(Object o){
return fastIsValid(o) && fullIsValid(o);
}
private static boolean fastIsValid(Object o){
// very fast function that returns true for 100% of valid objects
// returns false 99+% of invalid objects, returns true for <1%
}
private static boolean fullIsValid(Object o){
// very slow function that returns false for 100% of invalid objects
// returns true for 100% of valid objects
}
} We'd like to verify some properties of this function using unit tests:
We do not want to make fastIsValid() or fullIsValid() public, in this class or in another class: users should call isValid() in every conceivable circumstance.
Previously we were very happy with jmockit's mocking of private methods internal to our codebase, which allowed us to gain insight into this method during unit tests. If this feature is not going to be restored, could you please advise us as to the suggested approach for refactoring our class to enable testing these properties? |
I completely agree that the fastIsValid and fullIsValid methods should not be made public, since they clearly are implementation details of the Validator class, not meant for direct use in client code. For this same reason, they should not be mocked (or faked). Good tests (whether unit or integration tests) are supposed to verify behavior, not implementation. So, what you really need when testing the Validator class, is not to do those three bulleted points, which are obviously expressed in terms of the internal implementation of the class, but to write the tests in terms of its externally observed behavior. And since the class has no dependencies on other classes/types (or maybe fullIsValid has), there is nothing to mock in such tests. The comments inside those two private methods already suggest a better testing strategy. I can imagine the following three tests:
|
Thanks for the prompt reply. |
Version of JMockit 1.27
Both tests throwing an exception. With 1.25 or 1.26 there is no errror.
java.lang.IllegalArgumentException: Invalid mock method testbox.TestBox$2#getName2() for private method of internal class
at testbox.TestBox$2.(TestBox.java:42)
at testbox.TestBox.testGetName_fails2(TestBox.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
The text was updated successfully, but these errors were encountered: