How to test private methods
Jan 16, 2017 · 4 min read
To test a method you need to execute it, but calling private methods directly can be hard or even impossible, depending on the programming language you use. In this article I’ll primarily speak about Python and Java, but the described techniques surely can be applied to many other languages (but I can’t be sure about all of them).
What is a private method?
Have you ever asked yourself, why do you even need private methods? You need private data to maintain consistency, but why private methods?
Strictly speaking, you don’t. But they still be helpful at least for two major reasons:
- You want to extract some code that works with private data;
- You want to extract some code that doesn’t work with private data, but still doesn’t suit API (because user simple doesn’t care).
Whil e the first one prevents private data corruption, the second merely makes your API cleaner.
Don’t test it
Surprisingly, when I first came to Java programming and googled “How to test private method in Java”, the most popular answer was something like “Why do you want to test private methods? Users call public methods, test them instead”.
Well, that sounds crazy for me. I surely can just ignore the fact that a public methods call a private one, just imagine that private method code is inlined, but that means that code of the private method will be tested again and again with every public method that calls the private one.
In the following example you really want to test private method, not the two almost identical public ones.
One can notice that some refactoring can allow me not to test the private method. That’s true and we will talk about it later. But testing _set_status without any changes is still clean and reasonable way to do. I don’t buy this “don’t test private methods”.
Just call it
The simplest and most straightforward way to call a private method is, you know, call it. And that’s exactly what we do in Python and other languages that has private by convention (e. g. Perl).
To “just call it” in Java we need to change visibility of the method.
The first way is to make method package private (no access modifier) and put tests into the same package. This is a fairly common practice, but you still might want (or already have) another code structure.
The second way is to make method public. To let people know you still don’t want to call this method you can use @VisibleForTesting annotation from Guava or any other convention you like (that’s actually what Python and Perl do). By the way, IDEA totally understands that annotation and will warn you about using such public method outside of tests.
Nested class
You can also put a test class inside a tested one (at least in Java), but that doesn’t look great. You have to use the same file for both classes, and your production binaries will actually contain test code.
Reflection
In some languages reflections will do fine, in Ruby it’s that simple:
But in Java such code is so heavy I gave up on idea of providing an example here. More than this, you have to abandon all cool stuff your favourite IDE does for you.
Eliminate private
Personally I prefer the “just call it” method, and I like to use @VisibleForTesting in Java to make it happen.
But let us talk again about refactoring that allows me avoiding testing private methods (by eliminating them).
The point is to merge all private data and private methods into an object of another class that contains no private methods or data, but put the instance of that class into the only private attribute of the original class. Doesn’t sound simple, but it is, consider examples:
So now you can freely test EntityPrivateData , the only thing that remains private is data attribute. Like I said before, you actually don’t need private methods, only private data.
The described method can be useful not only for testing private methods, but also for more expressive design of your software. You can use any number of such private data classes so they have more sense semantically, not only technically.
For me, the most important thing about this pattern is that it proves that you technically can eliminate all private methods. But I still doubt that it’s reasonable to do it every time, your code can bloat without any significant benefit.
This article was written with the help of Nikolay Rys.
Источник
How to Unit test private methods in Java and Kotlin
Yes, This is a million-dollar question. How to unit test private methods?
Should a developer test the private methods in his codebase? or leaving them on the trust of public methods is a way. Every developer has its own opinion that whether should we actually test them or not. So, In a nutshell, the question got reduced to is “Is there exists any good approach we can try for this Job?”
So, here are all the possible options available to a developer to test private methods of his Java / kotlin based Apps in 2019:
- Don’t test private methods 😜 (No roots, no sour grapes)
- Give the methods public access 😒 (No, I won’t do this it’s against coding practices. I am a good developer, I follow best practices)
- Use a nested test class 😒 (This is not good to mixed production code with test code. Do I need to mention again that I am a good developer and I follow only best practices)
- Use Java Reflection 😃 (Yes, this seems interesting I’m in for it)
D espite the common belief it is actually possible to access private fields and methods of other classes via Java Reflection. It is not even that difficult. This can be very handy during unit testing.
Note: This only works when running the code as a standalone Java application, as you do with unit tests and regular applications. If you try to do this inside a Java Applet, you will need to fiddle around with the SecurityManager. But, since that is not something you need to do very often, it is left out of this text so far.
Method Parameter Reflection support was added in Java 8. Simply put, it provides support for getting the names of parameters at runtime.
Accessing Private Fields
To access a private field you will need to call the Class.getDeclaredField(String name) or Class.getDeclaredFields() method. The methods Class.getField(String name) and Class.getFields() methods only return public fields, so they won’t work. Here is a simple example of a class with a private field, and below that the code to access that field via Java Reflection:
This code example will print out the text “fieldValue = The Private Value” , which is the value of the private field privateString of the PrivateObject the instance created at the beginning of the code sample.
Notice the use of the method PrivateObject.class.getDeclaredField(«privateString») . It is this method call that returns the private field. This method only returns fields declared in that particular class, not fields declared in any superclasses.
Notice the line in bold too. By calling Field.setAcessible(true) you turn off the access checks for this particular Field instance, for reflection only. Now you can access it even if it is private, protected or package scope, even if the caller is not part of those scopes. You still can’t access the field using the normal code. The compiler won’t allow it.
Accessing Private Methods
To access a private method you will need to call the Class.getDeclaredMethod(String name, Class[] parameterTypes) or Class.getDeclaredMethods() method. The methods Class.getMethod(String name, Class[] parameterTypes) and Class.getMethods() methods only return public methods, so they won’t work.
Here is a simple example of a class with a private method, and below that the code to access that method via Java Reflection:
This code example will print out the text “returnValue = The Private Value” , which is the value returned by the method getPrivateString() when invoked on the PrivateObject the instance created at the beginning of the code sample.
Notice the use of the method PrivateObject.class.getDeclaredMethod(«privateString») . It is this method call that returns the private method. This method only returns methods declared in that particular class, not methods declared in any superclasses.
Notice the line in bold too. By calling Method.setAcessible(true) you turn off the access checks for this particular Method instance, for reflection only. Now you can access it even if it is private, protected or package scope, even if the caller is not part of those scopes. You still can’t access the method using the normal code. The compiler won’t allow it.
Let’s try this knowledge to some production-level code.
Here is the class containing some private methods which we want to test.
LoginPresenter.kt
Let’s test the private function saveAccount of loginPresenter
Источник
Android Testing :: testing private methods
This article is about testing private methods in android. This is a fairly common problem in android (even in Java at large) and can be solved easily. The technique proposed here provides the additionnal benefit of using a traditional way of solving the problem in the Java world. (suspense 🙂 )
Using the android platform, you are used to divide your application into two projects :
- one for the main source code of your application,
- one for the tests
This is a mandatory structure on android, stongly emphasized by Google. Even, if you use the android-maven-plugin, you follow this pattern, and it is also the case if you use robolectric.
Moreover, it is a common practice to name the packages of your application using the following convention (inside the AndroidManifest.xml files of both projects) :
Where foo.bar follows more or less your web domain name in the reverse order.
If you use the same package names to name the packages of your class, and this is a fairly common and intuitive practice, then you will face a big trouble : you will only be able to test your public methods : a test class inside a package named foo.bar.tests won’t be able to access the private and protected methods of a class in the package foo.bar . For instance :
In your app under test :
In your test app :
This code would generate a compile error. The method m() is only accessible to the classes that belong to the package foo.bar and the notion of subpackages doesn’t exist in the Java programming language.
Consequently you have several options.
1. Consider testing only public methods. Actually, this makes a lot of sense. Object-Oriented programming strongly emphasize the notion of contract and testing internals of a class can appear as violation of the notion of encapsulation.
Nevertheless, there are some cases where you really want to test some internal methods as they are complex, or just as they contain more of the logic of the class than public methods, or because you divided the different problems faced by public methods into some more specialized private methods (and this is a very good practice in IT, the famous divide and conquer principle).
2. Subclassing your class under test is an alternative : you can use protected methods in your class under test. And, in your tests, whenever you need to test a protected method, although you can’t invoke it directly, you can create a smaller inner class of the test class that extends the class under test and overrides every protected methods under test. This overridden method will just just invoke the super method, just to re-give it a package level visibility. The inner class protected methods will then be visible to the test class as they now belong to the same package.
Here is an example of this technique :
In your test app :
Although it is a common and accepted practice in Java to give a normally private method a protected visibility just to accomodate the case, purists are still under shock (and I belong to that camp), but that’s nevertheless a standard in Java. But this example demonstrates the drawback of this technique as well : it requires a huge, almost useless, amount of code, just a workaround and syntactic solution to a Java problem, but contains no interesting logic and is, indeed, a useless and thus painful programming effort. Nevertheless it could please purists as there is no need to alter the system under test only for testing purposes.
3. Using introspection is also possible. Reflexion allows to bypass the built-in visibility mechanism of Java. It allows to invoke any private / protected method on an object, or to use a private / protected field.
Here is an example :
In your test app :
Although this leads to some much more cryptic syntax and make you loose the ability to refactor your code easily (as you will have to hard code method under test names in your tests), this technique is only one that can be used to test a really private method. It will please purists as there is no need to alter the system under test only for testing purposes.
4. Avoid naming your Java packages in the same way as you name you Application package : in other words, there is absolutely no obligation to use the same name in your Java package and inside your AndroidManifest.xml.It was a bad idea from Google to call a “package” the app identifier inside an AndroidManifest file. This “package” is indeed an ID for your application inside google market for instance but it imposes no kind of constraints on Java packages inside your app and has indeed nothing to do with them.
Here is an example :
In your test app AndroidManifest.xml:
In your test app Java classes :
How does this work ? Simply because test classes and classes under test will be loaded inside the same Dalvik VM, all classes loaded from both apps and test-apps will be merged at runtime. Thus there is no difference in placing a class in an app or another on this specific matter (but please note that a class under test can’t depend on any class that is found in the test app dex/apk, this would result in an exception ‘ClassNotFoundException : class loaded from the wrong dex’ ).
Conclusion
This latter approach is much simpler than anything else and relies on the common Java practice of giving the protected visibility level to private methods for the sole purpose of testing them.
By using the same package for your test classes and your classes under test, you can test very simply internal methods and the package structure of your test app is much clearer.
Moreover, there is an additional benefit : you can use the eclipse “create junit test” wizard on your class under test (right click on the class under test and find it in the “ New >> JUnit Test Case ” option). Just change the source folder field of the wizard and choose your test app source folder instead of the app folder.
This article is the first of a serie of articles that will be dedicated to testability of android applications, one of the axis of research inside the Mobile Development Team @ Octo Technology.
Источник