简体   繁体   中英

Spring LocaleContextHolder not correctly set

I'm having some issues with Spring LocaleContextHolder .

I have the following code:

public void sendPasswordRecoverySmsAsync(String phone) {
    CompletableFuture.runAsync(() -> {
        sendPasswordRecoverySmsSync(phone);
    });
}

public void sendPasswordRecoverySmsSync(String phone) {
    User user = userDao.findByPhone(phone, User.class).orElseThrow(() -> new UserNotFoundException(phone));
    log.info("User found, recovering password");
    user.setUpdateTime(LocalDateTime.now());
    userDao.save(user);

    int otp = codesGenerator.generateOtp(user.getUpdateTime());

    // Sends the SMS.
    Locale locale = LocaleContextHolder.getLocale();
    System.out.println("locale " + locale);
    String appName = messageSource.getMessage("app.name", null, locale);
    String smsContent = messageSource.getMessage("sms.password.recovery", new Object[] { otp }, locale);
    Message message = new TextMessage(appName, phone, smsContent);
    try {
        smsClient.submitMessage(message);
    } catch (NexmoClientException | IOException e) {
        log.error("Error while sending recovery password message to phone number [{}]", phone, e);
        throw new UserActivationException("Error while recovering password for user with phone: " + phone, e);
    }
}

and this test:

@Before
public void setup() {
    LocaleContextHolder.resetLocaleContext();
    Mockito.when(tokenGenerator.generateOtp(Mockito.any())).thenReturn(14);
}

@Test(timeout = 3000)
public void testSendPasswordRecoverySmsAsyncError() throws Exception {
    // Mocks.
    LocaleContextHolder.setLocale(Locale.ENGLISH, true);
    String mockPhone = "333";
    User mockUser = mockModelBuilder.user(true, true);
    Mockito.when(userDao.findByPhone(mockPhone, User.class)).then(r -> {
        // TODO
        return Optional.of(mockUser);
    });
    CountDownLatch latch = new CountDownLatch(1);
    ArgumentCaptor<TextMessage> messageCaptor = ArgumentCaptor.forClass(TextMessage.class);
    Mockito.when(smsClient.submitMessage(messageCaptor.capture())).then(r -> {
        latch.countDown();
        throw new NexmoClientException();
    });

    // Test.
    service.sendPasswordRecoverySmsAsync(mockPhone);
    latch.await();

    // Assertions.
    Assert.assertTrue(true);
    TextMessage actualMessage = messageCaptor.getValue();
    Assert.assertEquals("myApp", actualMessage.getFrom());
    Assert.assertEquals(mockPhone, actualMessage.getTo());
    Assert.assertEquals("Your password recovery code for myApp app is 14", actualMessage.getMessageBody());
}

I would expect the ouput of my test being "en" and this works properly if I launch only this one. However, when I run all my tests, the ouput is "it". This is probably either because in other tests I set an ITALIAN locale or because it's getting the system default.

But why is it getting the wrong one even when I'm resetting it explicitly?

For solely the purpose of testing such localization cases, you might just need to add the following on your test method. This will essentially mark the context Dirty and recreate it, depending on whether you mention as the context being Dirty either before or After the test execution.

@DirtiesContext(methodMode = MethodMode.AFTER_METHOD)
@Test(timeout = 3000)
public void testSendPasswordRecoverySmsAsyncError() throws Exception {...

Please refer the documentation here

Hope this helps, as it resolved a similar problem for me.

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