10

I have a class that has the responsibility of importing contracts from a CSV to database.

The class itself has only one public method that starts the import and the other methods are all private (because only the class itself will use, and they hold the logic).

I'm starting to make tests for this class using Spock and there are many private methods, how should I test it?

Should I turn them into public to test? Test only the main method, the public one?

Whats the best?

Rui Vieira
  • 5,253
  • 5
  • 42
  • 55
Kennedy Oliveira
  • 2,141
  • 2
  • 20
  • 25
  • If you need to run a JUnit test against those methods, they need to be `public`. Would it cause any issues to do that? – Ascalonian Jan 15 '15 at 18:00
  • 1
    You could make those private methods into package methods (instead of public), and then your test just has to be in the same package. – Gus Jan 15 '15 at 18:00
  • 1
    I recommend reading through this SO post: http://stackoverflow.com/questions/105007/should-i-test-private-methods-or-only-public-ones – Bohuslav Burghardt Jan 15 '15 at 18:00
  • 2
    Spock tests are written in Groovy, which means that they can call private (Java) methods. So it's not a technical issue but merely a question of whether you *want* to go there. – Peter Niederwieser Jan 15 '15 at 18:10
  • @Ascalonian, it will break encapsulation. – Kennedy Oliveira Jan 15 '15 at 18:13
  • If private methods or fields are only used to access information (used in junit asserts), I sometimes promote them to package level. And encapsulation is not the same as data hiding. – Vytenis Bivainis Jan 20 '15 at 22:18
  • I like classes that have one public method that executes logic (for example, classes created through _extract method object_ refactoring), then there's no need to write method name in test. And if other methods give you access only to the results, I see no problem to promote their visibility. – Vytenis Bivainis Jan 20 '15 at 22:21

4 Answers4

16

In theory, your private methods are being used ultimately by one of the public methods, or else they're not used at all. So typically you setup your tests to call the public methods with the necessary context so that it hits your private methods.

The unit tests are primarily testing the compilation unit (i.e. the class). You can unit test methods directly but then they have to be public, which goes against having a nice clean API.

So test your public method enough to hit all the private methods. Private methods are internal mechanics of the class, they don't need to be tested directly.

mprivat
  • 21,582
  • 4
  • 54
  • 64
5

You can use reflection to achieve this. The Method class has a method called setAcessible(boolean) which enables you to call it even if declared as private/protected/default. See the example below:

YourClass yourClassInstance = new YourClass();
Method yourMethod = YourClass.class.getDeclaredMethod("yourMethod", null);
yourMethod.setAccessible(true);
Object[] parameters = new Object[1];
parameters[0] = "A String parameter";
Object result = yourMethod.invoke(yourClassInstance, parameters);
2

Some people argue that you should only test your API (i.e. your public methods).

A possible solution is to use package private so that only classes in the same package can access those methods.

Personally, I wouldn't test private methods, I would focus on the public methods behaving as expected. If you feel your private methods carry too much weight, then perhaps they do and you should separate further the functionality.

Rui Vieira
  • 5,253
  • 5
  • 42
  • 55
0

If your class implements an interface you can make "public" all methods you like to tests, but do not add them to interface. In this case you will be able to access to these methods from test but not from you src.

Vitaly
  • 2,552
  • 2
  • 18
  • 21