0

I'm learning mock and I wonder if I could use a code similar as this:

Mockito.when(service.authenticateUser(test)).thenReturn(any());

to validate the success of authentication.

service.AuthenticateUser(User user):

@Override
public Player authenticateUser(User login) throws AuthenticationException {
    Player find = new Player();

    for (Player player : initializedPlayers) {
            if (login.getEmail().equals(player.getEmail()) && login.getPassword().equals(player.getPassword())) {

            loggedPlayer = player;
            return player;
            }
    }
    throw new AuthenticationException("Incorrect email and/or password");
}

As you can see, the login method returns a Player, but is there a possible way to tell Mockito that I only want to get something back, if its valid? So I would be able to test wheter the authentication was succesful or not, e.g.:

Mockito.when(service.authenticateUser(test)).thenReturn(any(Player.class));
    assertNotNull(service.authenticateUser(test));

^this method currently not working, it gives failed test on stub.

EDIT: I tried approaching this in two different way:

@Test
public void testFailAuthWithMockedService(){
    DefaultSportsBettingService service = mock(DefaultSportsBettingService.class);
    User test = new User("test","test");
    Mockito.when(service.authenticateUser(test)).thenReturn(any(Player.class));
    assertNotNull(service.authenticateUser(test));
}
@Test
public void testSuccessfulAuthWithMockedService(){
    DefaultSportsBettingService service = mock(DefaultSportsBettingService.class);
    User test = new User("validName","validPassword");
    Mockito.when(service.authenticateUser(test)).thenReturn(any());
    assertNotNull(service.authenticateUser(test));
}

These codes comply, but I'm not sure if they are truely good.

Additional information: This method is called in my main at the very beginning:

 @Override
public Player authenticateUser(User login) throws AuthenticationException {
    Player find = new Player();

    for (Player player : initializedPlayers) {
            if (login.getEmail().equals(player.getEmail()) && login.getPassword().equals(player.getPassword())) {

            loggedPlayer = player;
            return player;
            }
    }
    throw new AuthenticationException("Incorrect email and/or password");
}

The main(): (that part of the main which uses the authentication)

 while(true) {
        try {
            dsbs.authenticateUser(view.readCredentials());
            if(dsbs.getLoggedPlayer() != null){
                break;
            }


        } catch (AuthenticationException ae) {
            ae.printStackTrace();
        }
    }
Mate25
  • 65
  • 6
  • The way to do this is to create a `User` object in your test and pass it to `thenReturn()`. – Code-Apprentice May 17 '22 at 16:32
  • Although...if you mock `authenticateUser()` in a test for `authenticateUser()`, you are only testing Mockito, not your code. – Code-Apprentice May 17 '22 at 16:33
  • Should I mock the User aswell? Or creat a stub? So basically: User user = new User("x","y"); / User user = mock(User.class); Mocikto.when(service.authenticateUser(test)).thenReturn(test); assertNotNull(service.authenticateUser(test)); – Mate25 May 17 '22 at 16:41
  • You don't need to use Mockito here at all from the information you have given us. Just creating a new user directly with known values is the ideal approach to your test. Additionally, `Mocikto.when(service.authenticateUser(test)).thenReturn(test);` still mocks the method you want to test. This means when you call `service.authenticateUser(test)`, you are calling the mock, not your code. Doing so completely invalidates the test because you are only testing Mockito, not your code. – Code-Apprentice May 17 '22 at 18:15
  • To make sure we are on the same page here, are the two lines you give at the end of your question the entire test? If not, will you [edit] your question to include the entire test so we have more context? Also include the entire error message in your question so that it can be easily searched by future visitors. – Code-Apprentice May 17 '22 at 18:22
  • @Code-Apprentice I updated the post, I hope it serves you with additional information about what I'm trying to do. – Mate25 May 18 '22 at 09:42
  • So your tests only test Mockito. They don't test your own `authenticateUser()` method. – Code-Apprentice May 18 '22 at 17:17

2 Answers2

3

You can't use any(...) in the thenReturn statement, that's where the error comes from.

This code should work:

Mockito.when(service.authenticateUser(test)).thenReturn(new Player(...));
assertNotNull(service.authenticateUser(test));

Now if you want to stub different results depending on the value of the login, you can use argumentMatchers in the when() part:

Mockito.when(service.authenticateUser(any(User.class))
  .thenThrow(AuthenticationException.class);
Mockito.when(service.authenticateUser(argThat(login -> list.contains(login))
  .thenReturn(new Player(...));

assertNotNull(service.authenticateUser(test));

Here the order is important: Mockito will try to match your argument in reverse order of stubs, so here it will first check if the login is in the given list, and if that stub fails, it will fall back to the first stub, which will throw an AuthenticationException for anything else.

If you want the returned Player to be dependent on the login User, you can use .thenAnswer() instead of .thenReturn(). See Mockito : doAnswer Vs thenReturn

GeertPt
  • 16,398
  • 2
  • 37
  • 61
  • "this code should work..." It compiles, but it doesn't actually test anything. I'm assuming that the OP is writing tests for `authenticateUser()`. On the other hand, if they are testing something else that calls `authenticateUser()`, then this is the right way to go. In such a case, the would need additional logic to call that other method and assert its results. – Code-Apprentice May 17 '22 at 18:17
  • 1
    @Code-Apprentice the OP started by saying he is learning how to use mocks. I tried to answer the technical question on how, not to expand on why or when. – GeertPt May 18 '22 at 12:03
  • I understand that point of view. Also, the original version of the question didn't show the context of where the mock was used. My assumption was the two lines of code shown in that version were a self-contained test, but on second reading, I could see how it might be in the context of another test. – Code-Apprentice May 18 '22 at 17:20
0
Mockito.when(service.authenticateUser(test)).thenReturn(any(Player.class));
assertNotNull(service.authenticateUser(test));

By mocking the return value of service.authenticateUser(test), you are testing Mockito, not your own code.

is there a possible way to tell Mockito that I only want to get something back, if its valid? So I would be able to test wheter the authentication was succesful or not

Don't use Mockito for this. Instead, you need to create a list of initializedPlayers and make it available to the authenticateUser() function. Ideally, you can just pass this list to the service object's constructor when you create it in your test. If not, then you have to create the players in a way that the service will get them when it needs to.

Similarly, you can create a test to verify that authenticateUser () throws AuthenticationException when the given user is not in the list of players.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268