简体   繁体   中英

How can I write unit tests for private methods of service and for public methods with private inside?

I have service:

@Slf4j
@Service
public class CashierServiceDefault implements CashierService {

  private final UserRepository userRepository;

  @Autowired
  public CashierServiceDefault(UserRepository userRepository) {
    this.userRepository = userRepository;
  }

  @Override
  @Transactional
  public CashierDto login(CashierDto cashier) {

    User dbUser = userRepository.findOneByLoginAndPassword(cashier.getLogin(), cashier.getPassword());

    validateCashier(cashier.getLogin(), dbUser);

    User userWithToken = createAuthToken(dbUser);

    return domainUserToCashierDto(userWithToken, cashier);
  }

  private void validateCashier(String login, User dbUser) {

    if (dbUser == null) {
      log.error("Cashier: {} not found", login);
      throw new AuthException(AuthException.ErrorCode.USER_NOT_FOUND_EXCEPTION);
    }

    UserRole userRole = UserRole.valueOf(dbUser.getUserRole().getCode());
    if (userRole != UserRole.CASHIER) {
      log.error("User: {} has role: {}. expected: CASHIER ", login, userRole.toString());
      throw new AuthException(AuthException.ErrorCode.USER_ROLE_NOT_PERMISSION_EXCEPTION);
    }
  }

  private User createAuthToken(User user) {
    user.setAuthToken(TokenGenerator.nextToken());
    user.setAuthTokenCreatedDate(new Date());
    return userRepository.save(user);
  }

  private CashierDto domainUserToCashierDto(User user, CashierDto cashier) {
    //mapping user's fields to CashierDto,s fields
    return cashier;
  }

I want create Test for this service. I tried this:

@RunWith(SpringRunner.class)
public class CashierServiceDefaultTest {

  @MockBean
  private UserRepository userRepository;

  private CashierService cashierService;

  @Before
  public void setUp() throws Exception {
    cashierService = new CashierServiceDefault(userRepository);
  }

  @Test
  public void login() {
    CashierDto cashierDto = new CashierDto();
    cashierDto.setLogin("Alex");
    cashierDto.setPassword("123");

    User user = new User();
    user.setLogin("Alex");
    user.setPassword("123");
    //and other test values

    when(userRepository.findOneByLoginAndPassword(cashierDto.getLogin(), cashierDto.getPassword())).thenReturn(user);

    CashierDto found = cashierService.login(cashierDto);
    assertThat(found.getAuthToken()).isEqualTo("123");
  }

And I have questions:

1. How can I tests private methods in my service? Do I need to test them? If so, how?

2. How should I test the public login method? I made a stub for repository methods:

when(userRepository.findOneByLoginAndPassword(cashierDto.getLogin(), cashierDto.getPassword())).thenReturn(user);

But should I do stubs for internal service methods?( validateCashier , createAuthToken , domainUserToCashierDto ). If so, how?

UnitTests do not test code , they verify public observable behavior which is return values and communication with dependencies .

private methods are implementation details which you test indirectly (as stated by JWo )

The reason is that you later may change your implementation details (refactor them) whithout breaking any of your existing UnitTests.

I would not test them directly. Since you implemented them as a help for some other methods, you can test those. By testing all public methods you will test the private ones, too. Don't forget to add inputs and outputs for the private methods, when testing the public ones.

Another way is to put test methods into the same package as the production code. Then you have to set your private methods to package or protected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM