I want to check a private method - is there something wrong with my design?

Therefore, I am extremely new to software testing, and I am considering adding a few tests to one of my applications. I have a public addKeywords () method that calls a private removeInvalidOperations () method along the way. This private method calls external API calls and is ~ 50 lines of code. Since I find this a somewhat complicated method, I would like to test this without doing this by calling the addKeyword () method. However, this is not possible (at least though JUnit).

The information I reviewed suggests that wanting to try out private methods may be the smell of code. Some people suggest that this may be a sign that it needs to be reorganized into a separate class and made public. In addition, there are suggestions that if you really need to, you can make changes to your production code, for example. change the visibility of the private method.

I really don’t understand why I have a problem with my current code design, but I also don’t like the idea of ​​editing my production code to suit my test needs.

As I said, I'm pretty new to testing, so any help is greatly appreciated. Also, please let me know if there is any additional information I can provide to help with the answers.

+11
java unit-testing integration-testing testing
Jan 25 2018-12-12T00:
source share
4 answers

I suggest refactoring.

The information I reviewed suggests that wanting to try out private methods may be the smell of code. Some people suggest that this may be a sign that it needs to be converted into a separate class and made public.

You have considered various reasons and against this in your own question, you seem to know the arguments well. But you have a method that seems rather complicated and includes an external API. It is worth checking out on your own. removeInvalidOperations() can still be a private method in the class it is in, but it will basically delegate another dependency.

 class YourClass { private OperationRemover remover; public void addKeywords() { // whatever removeInvalidOperations(); } private void removeInvalidOperations() { remover.remove(); } } 

This gives you the added benefit that you can replace this dependency at some point, including the ability to test your addKeywords() method without actually placing an external API call, which will make testing this method easier. OperationRemover can be an interface, for example, and for testing purposes, you just pass the stub instead, rather than the specific version used in the production process. As for your specific version, you can write tests for it no matter what happens to your existing class.

I really don’t understand why I have a problem with my current code design, but I also don’t like the idea of ​​editing my production code to suit my requirements. tests.

Lighter testability is a side effect. Look at it differently: what you are actually doing makes the code loosely coupled and extensible. Above, we have separated the call from the external API from the code, which may require the use of the result. The external API is subject to change. You can go from one service to another, but code that uses the result should not care. This class can remain unchanged, only the class that actually places calls must be modified (or replaced).

Real world example: Year 2007, and you work at a bank in a large financial center in the United States. The application must use account information. Your code gets to any web service inside the bank and receives the necessary information in the form that it needs, and then continues its processing. In 2008, the US financial sector is unleashed, and your bank (which is on the verge of collapse) is absorbed by another bank. Your application has been spared, but now you need to turn to another API that already exists in the surviving bank in order to get account information. Should the code that consumes this account information be changed? Not necessary. This is the same account information as before, only from a different source. No, all that needs to be changed is the implementation that calls the API. Consumption code should never know.

The fact that such free communication also contributes and facilitates testing is a bonus.

+13
Jan 25 '12 at 2:12
source share

If it is private , it cannot be considered part of your application API, so testing is really the smell of code - when the test is interrupted, is this normal or not?

Unit tests should be functionally oriented, not code oriented. You are testing units of functionality, not units of code.

Regardless of the philosophy, a class outside your implementation cannot access a private method without hacking the JVM, so you are out of luck - you either need to change the visibility of the method or make the test API protected test class extend or test the function indirectly by calling public methods using her.

+7
Jan 25 2018-12-12T00:
source share

Usually you do not want to check the private method, but there are exceptions.

You may be tempted to test a private method if:

  • You didn’t think about how to test a private method indirectly by invoking existing public methods.

  • Your class API is too inflexible. Public methods need more parameters or some private methods must be made public.

  • Your class’s API is flexible enough, but there are open-air methods that have some pretty complicated private methods below.

Based on your question, you can be in any of these cases.

For (1), obviously, you should first try to find a way to test your private method with existing public methods.

For (2) and (3), unit tests will not tell you which case you are in. What you need to do is write sample code. As Josh Bloch recommends , indicate some use cases for your API. Your API should be the minimum set of public methods needed to satisfy your use cases.

(3) - this is the case when he checks private methods. There are various tricks for this. For production code, they are better than exposing your method to an API user (making it publicly available) so that you can test it. Or dividing related functions into 2 classes so you can test it.

Instead of thinking in terms of “code smells,” which is inaccurate and subjective, you can think in terms of hiding information . Solutions that are subject to change should not be disclosed in your public API. Preferably, design decisions that are subject to change should also not be subjected to your unit tests - why people recommend not testing private methods.

But if you really consider it important to conduct a unit test of your private method, and if you can not do it using public methods, do not sacrifice the correctness of your code! Check out the private method. The worst case is that your test code is more messy and you should rewrite the tests when the private method changes.

+4
Jan 25 '12 at 2:21
source share

If you don't want to call addKeywords() , perhaps you should just add another public method, testRemoveInvalidOperations() , which simply calls private removeInvalidOperations() . You can delete the test later.

0
Jan 25 2018-12-12T00:
source share



All Articles