0

I have the service class:

@Service
@RequiredArgsConstructor
public class UserService {

    private final UserRepository userRepository;

    @Transactional
    public void registerUser(User user) {
        user.setPassword(DigestUtils.md5Hex(user.getPassword()));
        userRepository.save(user);
    }
}

And I have the following test:

@RunWith(MockitoJUnitRunner.class)
public class UserServiceTests {

    private UserRepository userRepository = Mockito.mock(UserRepository.class);

    private UserService userService = new UserService(userRepository);

    @Test(expected = Exception.class)
    public void testCreateUser(){
        User user = new User(null, "Glass", "123123", "glass999@mail.ru");
        when(userRepository.save(null)).thenThrow(new Exception());
        userService.registerUser(user);
    }
}

And my question is why the test passes?? It must passes only when userRepository's save method accepts null. But I pass user object, not null, and save method actually accepts user object. Does anyone know the answer?

Daimon
  • 345
  • 1
  • 5
  • 21

2 Answers2

0

Check what exception you get when you run the test. I am assuming it will be a Spring DAO Exception. You are mocking userRepository but the condition defined is on absolute value, i.e. null

 when(userRepository.save(null)).thenThrow(new Exception());

So the mocked method is invoked only when you call userRepository with an absolute argument as null. In your case I don't think its invoking the mocked method. Rather it's trying to invoke the actual method on userRepository reference which is throwing an exception.

So you do get an exception but its not due to the mocked condition/method defined.

You can debug and confirm what exception is being thrown and that should clarify.

varkashy
  • 374
  • 4
  • 18
  • When I run a test I don't get an exception, It's okay. Test passes. But it doesn't have to – Daimon Jun 19 '18 at 15:01
  • you should be getting an exception right? your test expects an exception `@Test(expected = Exception.class)` – varkashy Jun 19 '18 at 15:03
  • Yes, the test should be getting Exception.class and it gets it. But in order to throw the exception, I need to pass the null object. But I don't pass null. Why is the exception thrown? – Daimon Jun 19 '18 at 15:11
  • as i said, i dont think that exception is coming because of `when(userRepository.save(null)).thenThrow(new Exception());` Since you call `userRepository.save(user)` and not by passing null, it actually invokes real method and the mocked when-then clause is not executed. You should be able to see the exception type to confirm. – varkashy Jun 19 '18 at 15:11
  • I can remove null and set another user object(User A). But when I pass User B it still passes the test – Daimon Jun 19 '18 at 15:28
  • yeah, as i said, you are not setting the when-then condition properly. When you set an absolute condition e.g. `when(someObject.method("name")).thenReturn()` now this when-then condition will only work for string "name", as it is absolute value. If you pass something else `someObject.method("your name"))` this will call real method and mock when-then will not take affect. To make it work for any string, you need to set it for all strings and not absolute `when(someObject.method(anyString())).thenReturn()`. Your test passes but for wrong reason, you get exception as real method is invoked. – varkashy Jun 19 '18 at 15:33
  • you should be able to debug and confirm that the exception you get is not because of your mock when-then clause , rather it will be coming from repository layer – varkashy Jun 19 '18 at 15:34
  • Thanks, I changed exception to ArrayIndexOfBoundException for example sake)) it works. It's weird because I use SpringData and repository works well, I've already added users using this method. But thanks) – Daimon Jun 19 '18 at 16:27
0

I found the reason. The problem was that userRepository.save method doesn't have Exception exception in its signature. Here the similar problem

Daimon
  • 345
  • 1
  • 5
  • 21