1

How do I test private methods and a method with 2 controls in it? How can I write a test method for the create method and for the private checkUsername method?

public User create(User user) {
    checkUsername(user.getUsername());
    return userRepository.save(user);
}
private void checkUsername(String username) {
    if (username.equals("dummy")) {
        String msg = String.format("Username = '%s is cannot be used!", username);
        throw new UsernameUnavailableException(msg);
    } else if (!userRepository.existsByUsername(username)) return;

    String msg = String.format("Username ='s%s' is being used by another user!", username);
    throw new UsernameIsInUseException(msg);

}

I couldn't find a private method test according to my research, can you help me?

bighugedev
  • 379
  • 1
  • 3
  • 11
  • 2
    You don't. You test the methods that call those private methods and make sure you're testing all possible paths. `create`, in this case, so passing a `User` with `username` (I suppose) `"dummy"`, and a different string, and `null` (which will make `checkUsername` throw a `NullPointerException`, by the way). – Federico klez Culloca Nov 07 '22 at 07:44
  • 1
    The private method is immaterial. Simply test if you get the expected output, whether that be a `User` object or an exception, given a certain input. And if you've defined your class correctly, then you'll be able to insert a mock for `userRepository` so that you don't interact with a real data source. – Slaw Nov 07 '22 at 07:45
  • @FedericoklezCulloca i have to do it was given as homework and i don't know how to do it if you can write it can you send the code – taha furkan ünsal Nov 07 '22 at 07:48
  • @tahafurkanünsal please read [Open letter to students with homework problems](https://softwareengineering.meta.stackexchange.com/q/6166). Sorry, but we're not doing your homework for you. If you don't know how to do it review the course material, because the answer is surely in there. If that's still unclear ask your tutor/teacher. That's what they're there for. – Federico klez Culloca Nov 07 '22 at 07:50
  • 1
    No, I will not do your homework for you. From a testing perspective, pretend that the private method doesn't exist, and all that code is actually inlined into the `create(User)` method. In other words, you test `create(User)` and make sure it returns what you expect when you expect it and throws an exception when you expect. For the most part, you only care about the _what_, not the _how_. – Slaw Nov 07 '22 at 07:52
  • @FedericoklezCulloca how should i do it for private method at least one place i should look is an example – taha furkan ünsal Nov 07 '22 at 07:54

2 Answers2

3

The Right Way

You would not be testing the method checkUsername directly, you should be testing it indirectly by testing your create method.

You have 3 tests from what I can see that you need to create:

  1. Test the outcome when username is dummy - you want to be testing for the expected exception of UsernameUnavailableException with the message of Username = 'dummy' is cannot be used!.
  2. Test the outcome is UsernameIsInUseException when a username already exists and the expected exception error message is Username = '<insert username>' is being used by another user!.
  3. Test what actually happens when the user is successfully saved.

If this was me I would be looking at creating a mocked/spied version of userRepository so I could manipulate the response for both existsByUsername and save for each individual test. I would also assert how many times those methods get called for each test, for example for test (1) I would not expect either existsByUsername or save to be called so I would verify that it was called 0 times. Whereas for test (2) I would expect existsByUsername to be called at least once and save to be called 0 times; and for test (3) I would expect both methods to be called at least once and only once.

If you cannot test a private method indirectly then it most likely falls into one of 3 categories:

  1. The private method is dead code because it cannot be indirectly accessed.
  2. Your code has been poorly designed and you should consider refactoring to be more efficient.
  3. The method you are trying to test should never have been private in the first place, does it make sense from a design point of view to make it public?

The Wrong Way

The wrong way would be to use reflection to access that private method, unfortunately I know people who swear by this method but in my opinion it is the wrong way to carry out tests of a private method; and unfortunately I have used reflection myself to test a private method within a legacy project in which I was unable to refactor so would have fallen into category 2 above.

The snippet below is from a book called JUnit In Action, I would recommend picking up a copy if you can.

Using reflection to access private properties and methods breaks what we learn as a good student and well disciplined developer, and that is the object-oriented language is built around 3 pillars: encapsulation, inheritance and polymorphism

I have not shared code because this is clearly a homework question, however above should be enough to help guide you towards achieving what you need.

Popeye
  • 11,839
  • 9
  • 58
  • 91
-4

Actually, you can use ReflectionTestUtills to achieve that, please read below https://www.baeldung.com/spring-reflection-test-utils