if...else statement issue in mockito test in Spring Boot

HungryBird :

how to write a mockito test case for if...else statement which also includes exception test, I am quite confused about this. UserService is an interface

UserFactory.java

public class UserFactory {
    @Autowired
    private List<UserService> UserList;

    private final Map<String, UserService> UserMap = new HashMap<>();

    @PostConstruct
    public void initUserMap() {
        for (final UserService user : UserList) {
            UserMap.put(user.getUserId(), user);
        }
    }

    public UserService getUser(String userId) {
        final UserService userService = UserMap.get(userlId);
        if (null == userService) {
            throw new IllegalArgumentException("user are not in the group");
        }
        return userService;
    }
}

UserService(Interface)

public interface UserService{
  String getUserName();
  String getUserId();
}

here is my test, but it is not correct...

@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {

    @Mock
    private UserService userService;

    @InjectMocks
    private UserFactory UserFactory;

    private Map<String, User> UserMap;

    private String userId = "123";

    @Before
    public void set_up(){
        UserMap = new HashMap<>();
        UserMap.put(userId, userService);
    }

    @Test
    public void getUser(){
        when(UserMap.get(userId)).thenReturn(userService);
        userService actual = userServiceFactory.getUser(userId);
        assertEquals(UserMap.get(userId), actual);
    }
}
davidxxx :

1) You write an unit test, not a sliced test or an integration test. So here Spring Boot doesn't matter as you don't need to load a container to test the logic of your component.
You can read my question/answer about this field if you are interested in.

2) A branch (if/else) in the logic means that you have multiple scenarios.
Distinct scenarios mean generally distinct test methods and meaningful names.
You can also rely on the given/when/then idiom.

3) Since in your test the input information for the branch is provided by the mock, it also means that you will register distinct behaviors for the mock in each test method.

4) UserService doesn't need to be mocked. It has to be a value returned by the mock not the mock itself. Here you have to mock the Map.

5) You test UserFactory, so you have to name it UserFactoryTest .

For example :

@RunWith(MockitoJUnitRunner.class)
public class UserFactoryTest {

    @Mock
    private Map<String, User> UserMap;

    @InjectMocks
    private UserFactory UserFactory;

    private String userId = "123";


    @Test
    public void getUser(){
       when(UserMap.get(userId)).thenReturn(userService);
       userService actual = userServiceFactory.getUser(userId);
       assertEquals(UserMap.get(userId), actual);
    }


    @Test
    public void getUser_with_unknown_userId(){
        Assertions.assertThrows(IllegalArgumentException.class, 
                            ()->  userServiceFactory.getUser(userId));
    }

}

You notice that in the second case I don't register any behavior for the mock.
By default Mockito will return null and actually it is what I need to provoke the exception. So it is fine.
Note also that I wrote the assertion by relying on the JUnit 5 library and not the JUnit 4 library that you seem to use according the used runner.
You should consider to switch to JUnit 5 for new tests.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=81668&siteId=1