InterruptedException and TaskRejectedException in SpringBootTest with Async service - java

I am testing using SpringBootTest. One of the services behind uses an asynchronous service running with an Executor service that has 50 threads.
But I am getting Shutting Down ExecutorService asycnExecutor, InterruptedException then TaskRejectedException .... [shutting down pool size =8, active thread = 8] did not accept task.
Here the threadname is pool-3-thread-1 and parent is main i assume this is from the SpringBootTest. Also it seems 8 tasks have been created and accepted but shutdown after that
Also no message in InterruptedException when I caught it specifically. message is null;
I figured the following:
Something is shutting down the executor service when its running
Then it goes through interrupted exception and shutsdown
Rest of the tasks gets TaskRejectedException becuase executorservice
shutsdown
Sample Code (tried to simplify as much as possible):
#SpringBootApplication
#EnableCaching
#EnableScheduling
#EnableAsync
public class App extends springBootServletInitializer
{
public static voice main(String[] args){
SpringApplication.run(App.Class, args)
}
#Bean(name = "asycnExecutor")
public Executor asycnExecutor() {
ThreadPoolTaskExecutor exc = new ThreadPoolTaskExecutor();
//setcore = 50;
//setmaxpool = 1000
//setqueue = 2000
//setthreadnameprefix = "customAsycn"
//initialize
return exc;
}
}
NormalService.java
#Component
public class NormalService{
#Autowired
MyAsycnService myasyncService;
#Cacheable("myobject")
public MyObject someservice(){
do_someService();
}
#CachePut("myobject")
public MyObject do_someService(){
if(many){
/// some steps
foreach()
{
CompletableFuture<myobject> blah = myasyncService.doTask();
}
//allof / join / .get on the list of CompletableFuture<Void> and accumulate result
}
else {
///some otherstep
CompletableFuture<myobject> blah myasyncService.doTask();
//just 1 result
}
return myObject;
}
}
MyAsycnService.java
#Service
public class MyAsycnService {
#Autowired
RestTemplate restTemplate;
#Asynch("asycnExecutor")
public CompletableFuture<MyObject> doTask()
{
ResponseEntity<string> r = restTemplate.getEntity();
MyObject myobject = process(r);
return CompletableFuture.completedFuture(myobject);
}
private MyObject process(ResponseEntity<responseEntity> r)
{
MyObject o = new MyObject();
///someprcess
return o;
}
}
ScheduledControllerCallerConfig
#Component
pulic class ScheduledClass {
#Autowired
NormalService ns;
#Scheduled (fixedDelay = 10000, initialDelay = 500)
public void do_something()
{
ns.someservice();
}
}
MyController.Java
#Controller
public class MyController {
#AutoWired
NormalService ns;
#ApiOperation
#RequestMapping
public ResponseEntity<MyObject> getSomething()
{
MyObject = ns.someservice();
return ResponseEntity.ok(result);
}
}
Tests;
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) // also tried with classes = App.class
#Autowired
TestRestTemplate restTemplate
#Mock
MyObjectmyobject
#Test
public void testResponse() {
}
please help figure why it fails in the integration tests or some directions for debugging further?

Related

Spring boot #Retryable Mock test fails

Test case fails to retry multiple times (2), it tries once and the exception is thrown
my application class has EnableRetry annotation
#SpringBootApplication
#ComponentScan("com.***")
#EnableJpaAuditing
#EnableRetry
public class Application {
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
}
}
This is the service class that has the method I want to retry.
#Service
#RequiredArgsConstructor
#Slf4j
#EnableRetry //just in case, this didn't help though!!
public class DataSetService {
//some objects
private int count;
.....
#Scheduled(fixedRate = 86400000)
#Retryable(value = {OptimisticLockException.class}, maxAttemptsExpression = 2, backoff =
#Backoff(delayExpression = 1000))
public void updateDataSetExp() {
LOG.info("Count : " + count++); //Expecting this count to be 3 after re-tries
Date dateBeforeExpiry = new Date(System.currentTimeMillis() - THIRTY_DAYS_IN_MS);
List<DataSet> expiredDataSets =
dataSetRepository.findByCreatedAtBefore(dateBeforeExpiry);
for (DataSet expiredDs : expiredDataSets) {
expiredDs.setExpired(true);
dataSetRepository.save(expiredDs);
}
}
}
#Recover
public void updateDataSetExpFallback(OptimisticLockException e) {
LOG.error("Optimistic locking issues found");
}
My test case
#RunWith(SpringRunner.class)
#SpringBootTest
public class DataSetServiceRunnerTest {
#Autowired
private DataSetService dataSetService;
DataSetCreateRequest dataSetCreateRequest;
DataSet dataSet;
#MockBean
DataSetRepository dataSetRepository;
//all other mock beans that are required
#Before
public void setup(){
dataSetService = new DataSetService(dataReferenceRepository, dataSetRepository,
principalService,userInfoService, ccStorageService, elasticConfiguration,
clusterRepository, encryptionService, awsService);
dataSet = new DataSet();
}
#Test
public void testUpdateDataSetExpiryOptimisticLock(){
List<DataSet> expiredDataSetList = new ArrayList<>();
expiredDataSetList.add(dataSet);
when(dataSetRepository.findByCreatedAtBefore(any(Date.class)))
.thenReturn(expiredDataSetList);
when(dataSetRepository.save(any(DataSet.class)))
.thenThrow(OptimisticLockException.class);
try {
dataSetService.updateDataSetExp();
} catch (OptimisticLockException e){
System.out.println("Exception caught");
}
verify(dataSetRepository, times(3)).save(dataSet);
verify(dataSetRepository, times(3)).findByCreatedAtBefore(any(Date.class));
}
}
I am expecting dataSetRepository.findByCreatedAtBefore method to be invoked 3 times and then the exception is thrown but in my case, it is only invoked once. also, the count is expected to be 3 but is 1.
I've tried looking into other posts and followed the documentation around Retryable but didn't help. Can someone provide some pointers.
In your test case setup() is not required ideally because #SpringBootTest will load Spring context and all Beans will be initialized explicitly.
Also, I tried to replicate your setup and it seems to be working fine with and without #Scheduled
#Slf4j
#Service
#AllArgsConstructor
public class RetryDirectService {
private final TestService testService;
#Retryable(value = NumberFormatException.class, maxAttempts = 4, backoff = #Backoff(500))
#Scheduled(fixedRate = 10000)
public String getData() {
return testService.getData();
}
#Recover
public String recoverData(String appender) {
log.info("Calling recoverData");
return "DEFAULT";
}
}
#SpringBootTest
public class RetryDirectServiceTest {
#Autowired
private RetryDirectService retryDirectService;
#MockBean
private TestService testService;
#Test
public void testShouldRetryTillMaxAttemptsAndCallsRecoveryBlock(){
//Given
Mockito.when(testService.getData()).thenThrow(new NumberFormatException());
//When
retryDirectService.getData();
//Then
verify(testService, Mockito.times(4)).getData();
}
}
The only deviation was that with #Scheduled, getData() was called 5 times. Which is expected. 4 times for retry and one time when triggered by the scheduler.
For more detail in Retry setup plase refer this post

Multithreading in Spring Boot

I am completely new to Spring. Trying to call a method on a separate thread using Spring Async annotation. This is the code I have tried after looking around a bit:
public class MyClass {
private static final Logger LOGGER = LoggerFactory.getLogger(MyClass.class);
#Async("threadPoolTaskExecutor")
public void asyncMethodWithVoidReturnType() {
System.out.println("Hello from sout! Execute method asynchronously. " + Thread.currentThread().getName());
LOGGER.info("Hello from logger! Execute method asynchronously. " + Thread.currentThread().getName());
}
}
and the runner:
#SpringBootApplication
#EnableAsync
public class SpringTestRunner {
#Bean("threadPoolTaskExecutor")
public Executor getAsyncExecutor() {
return new ThreadPoolTaskExecutor();
}
public static void main(String[] args) {
SpringApplication.run(SpringTestRunner.class, args);
}
}
When running the main class, I do not see any output from the thread. Why is that?
As you can tell, this is a very basic question, so please explain as much as you can.
You don't see output because you don't call your asyncMethodWithVoidReturnType function. Example with scheduler:
Writer:
#Slf4j
#Service
public class AsyncWriter {
#Async("threadPoolTaskExecutor")
#SneakyThrows
public void asyncWrite() {
log.info("Hello! " + Thread.currentThread().getName());
Thread.sleep(1000);
}
}
Scheduler:
#Slf4j
#Service
#RequiredArgsConstructor
public class Scheduler {
private final AsyncWriter asyncWriter;
#Scheduled(fixedDelay = 1000)
public void scheduledWrite() {
log.info("Scheduler");
for(int i = 0; i < 10; i++) {
asyncWriter.asyncWrite();
}
}
}
Runner:
#SpringBootApplication
#EnableAsync
#EnableScheduling
public class SpringTestRunner {
#Bean("threadPoolTaskExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
return executor;
}
public static void main(String[] args) {
SpringApplication.run(SpringTestRunner.class, args);
}
}

Run a process asynchronously after completion of initial process in Spring boot

I have a requirement. I have 2 processes
Contact creation and
Associating contact to the Department
Currently I have a spring boot API which has a REST POST call to perform both in one thread. Since process 2 is taking more time I wanted to run that in the
background immediately after finishing the step 1.
#PostMapping(value = "/processDeptContact", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PayloadResponse> processDeptContact(#RequestBody String payload) {
ResponseEntity response = new ResponseEntity(new ErrorResponse("Exception"),
new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
try {
response = myService.processPayload(payload);
} catch (Exception e) {
logger.error("Exception in the controller");
}
return response;
}
I want to return the response to the user as soon as step 1 is done and performing step 2 at the background. How do I achieve that
Thanks in advance
In your main class, or a #Configuration class, use #EnableAsync to bootstrap a thread pool:
#EnableAsync
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
You can optionally set Thread Pool properties under spring.task.execution.pool property. Example:
spring:
task:
execution:
pool:
core-size: 8
max-size 16
Here's a stack post detailing what each property means: Core pool size vs maximum pool size in ThreadPoolExecutor
Inside your controller:
#RestController
public class TestController {
private final ContactService contactService;
private final DepartmentService departmentService;
// Constructor Injection
public TestController(ContactService contactService, DepartmentService departmentService) {
this.contactService = contactService;
this.departmentService = departmentService;
}
#PostMapping(value = "/processDeptContact", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PayloadResponse> processDeptContact(#RequestBody String payload) {
List<Contact> contacts = contactService.processPayload(payload);
departmentService.associateContacts(contacts); // This is an asynchronous call
return ResponseEntity.ok(new PayloadResponse(contacts));
}
}
I've removed the try/catch from the controller method since error handling is a cross cutting concern and is handled by AOP. More on that here: Baeldung
And finally in your DepartmentService, you use the #Async annotation to turn it into an asynchronous method:
#Service
public class DepartmentService {
#Async
public void associateContacts(List<Contact> contacts) {
// method
}
}
I see other answers are basically saying the same thing and are correct, but not complete so I felt the need to put everything together for you.
Spring framework provides support for asynchronous processing out of the box. Spring can create & manage threads for us by providing support for various TaskExecutor abstraction.
We can create a method in a new class that will do the second process (associate contact to the Department) and annotate that method with #Aysnc. The annotation ensures the spring executes this method as a Runnable/Future depending on return type.
Sample Implementation (We have to add #EnableAsync in any of our configuration class)
#Component
class ContactManager {
#Async
public void associateContactToDepartment(){
//method implementation goes here
}
}
class MyService {
#Autowired
private ContactManager contactManager;
public PayloadResponse processPayload(String payload){
payloadResponse payloadResponse = createContact();//first process
contactManager.associateContactToDepartment() // this call will be executed asynchronously.
return payloadResponse;
}
}
Refer this for quick intro to async methods.
Follow the below steps:
Add #EnableAsync annotation and Add TaskExecutor Bean to main spring boot application class
#SpringBootApplication
#EnableAsync
public class AsynchronousSpringBootApplication {
private static final Logger logger = LoggerFactory.getLogger(SpringBootApplication.class);
#Bean(name="processExecutor")
public TaskExecutor workExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setThreadNamePrefix("Async-");
threadPoolTaskExecutor.setCorePoolSize(3);
threadPoolTaskExecutor.setMaxPoolSize(3);
threadPoolTaskExecutor.setQueueCapacity(600);
threadPoolTaskExecutor.afterPropertiesSet();
logger.info("ThreadPoolTaskExecutor set");
return threadPoolTaskExecutor;
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootApplication.class,args);
}
Add the contact to department method as below:
#Service
public class DepartmentProcess {
private static final Logger logger = LoggerFactory.getLogger(ProcessServiceImpl.class);
#Async("processExecutor")
#Override
public void processDepartment() {
logger.info("Received request to process in DepartmentProcess.processDepartment()");
try {
Thread.sleep(15 * 1000);
logger.info("Processing complete");
}
catch (InterruptedException ie) {
logger.error("Error in ProcessServiceImpl.process(): {}", ie.getMessage());
}
}
}
Call the method from the controller as below:
#PostMapping(value = "/processDeptContact", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PayloadResponse> processDeptContact(#RequestBody String payload) {
ResponseEntity response = new ResponseEntity(new ErrorResponse("Exception"),
new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
try {
response = myService.processPayload(payload);
myService.processDepartment();//async method
} catch (Exception e) {
logger.error("Exception in the controller");
}
return response;
}
Points 1 and 2 are not here but it doesn't matter, let's call them foo1() and foo2().
In myService.processPayload() you want to do:
ResponseEntity result = foo1();
Runnable runnable = () -> {
foo2()
};
Thread thread = new Thread(runnable);
thread.start(); // the logic in foo2 will happen in a background thread so it will not block on this line, consider using a thread pool instead
return result;
BTW, this sounds like premature optimization and you should think about race conditions with parallel threads but this is not what the question was asking.
One more thing, move this to the catch because it's a waste of instantiations if the try will succeed, which should happen most of the time.
ResponseEntity response = new ResponseEntity(new ErrorResponse("Exception"),
new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);

Spring Boot #Async method executing synchronously

This is very similar to the other question here: Spring Boot #Async method in controller is executing synchronously. However my #Service method annotated with #Async is still executing synchronously. I've tried all methods from different forums to no use. Hopefully someone could help me figure out why. A simple spring boot project as below doesn't work.
AsyncConfiguration.java
#Configuration
#EnableAsync
public class AsyncConfiguration(){}
SomeService.java
#Service
public class SomeService() {
#Async
public void doSomething() {
try {
Thread.sleep(5000L);
} catch (Exception ignore){}
}
}
SomeController.java
#Controller
public class SomeController() {
#Inject SomeService someService;
#RequestMapping(value="/", method=RequestMethod.POST)
public String doStuff() {
someService.doSomething();
return "mytemplate";
}
}
Here is a simple example with #Async. Follow these steps to get #Async to work in your Spring Boot application:
Step 1: Add #EnableAsync annotation and Add TaskExecutor Bean to Application Class.
Example:
#SpringBootApplication
#EnableAsync
public class AsynchronousSpringBootApplication {
private static final Logger logger = LoggerFactory.getLogger(AsynchronousSpringBootApplication.class);
#Bean(name="processExecutor")
public TaskExecutor workExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setThreadNamePrefix("Async-");
threadPoolTaskExecutor.setCorePoolSize(3);
threadPoolTaskExecutor.setMaxPoolSize(3);
threadPoolTaskExecutor.setQueueCapacity(600);
threadPoolTaskExecutor.afterPropertiesSet();
logger.info("ThreadPoolTaskExecutor set");
return threadPoolTaskExecutor;
}
public static void main(String[] args) throws Exception {
SpringApplication.run(AsynchronousSpringBootApplication.class,args);
}
}
Step 2: Add Method which executes an Asynchronous Process
#Service
public class ProcessServiceImpl implements ProcessService {
private static final Logger logger = LoggerFactory.getLogger(ProcessServiceImpl.class);
#Async("processExecutor")
#Override
public void process() {
logger.info("Received request to process in ProcessServiceImpl.process()");
try {
Thread.sleep(15 * 1000);
logger.info("Processing complete");
}
catch (InterruptedException ie) {
logger.error("Error in ProcessServiceImpl.process(): {}", ie.getMessage());
}
}
}
Step 3: Add an API in the Controller to execute the asynchronous processing
#Autowired
private ProcessService processService;
#RequestMapping(value = "ping/async", method = RequestMethod.GET)
public ResponseEntity<Map<String, String>> async() {
processService.process();
Map<String, String> response = new HashMap<>();
response.put("message", "Request is under process");
return new ResponseEntity<>(response, HttpStatus.OK);
}
I have also written a blog and a working application on GitHub with these steps. Please check:
http://softwaredevelopercentral.blogspot.com/2017/07/asynchronous-processing-async-in-spring.html
Sorry for my English.
The same problem happened to me.
The solution was to add
#Autowired
private SomeService someService;
In the Controller class, in this way it allows the class to contain the Beam Configurations associated with "SomeService", thus being able to execute the asynchronous method perfectly.
Here is a project with a functional asynchronous method:
https://github.com/JColmenares/async-method-api-rest.git

Using autowired dependencies with certain mock dependency in Spring4

I have a rest resource for signup and login. both in a controller class. the controller class has a dependency to a service class with the business logic. the service class has further dependencies. cause i use an embedded db for testing, i want to use the real dependencies of my app instead to mock them with something like #injectmock #mock. there is only one certain dependency i have to mock. its the dependency for sending emails after a signup process. how to write test cases with #autowired function and one certain mock dependency for email notification?
#Controller
public class AccountCommandsController {
#Autowired
private LogoutService service;
#RequestMapping(value = "/rest/login", method = RequestMethod.POST)
public ResponseEntity login(#RequestBody Account account) {
AccountLoginEvent accountLoginEvent = service.loginAccount(new RequestAccountLoginEvent(account.getEmailAddress(), account.getPassword()));
if (accountLoginEvent.isLoginGranted()) {
return new ResponseEntity(HttpStatus.ACCEPTED);
} else {
return new ResponseEntity(HttpStatus.UNAUTHORIZED);
}
}
#RequestMapping(value = "/rest/signup", method = RequestMethod.POST)
public ResponseEntity signup(#RequestBody Account account) {
AccountSignupEvent signedupEvent = service.signupAccount(new RequestAccountSignupEvent(account.getEmailAddress(), account.getPassword()));
if (signedupEvent.isSignupSuccess()) {
return new ResponseEntity(HttpStatus.ACCEPTED);
} else if (signedupEvent.isDuplicateEmailAddress()) {
return new ResponseEntity(HttpStatus.CONFLICT);
} else if (signedupEvent.isNoSignupMailSent()) {
return new ResponseEntity(HttpStatus.SERVICE_UNAVAILABLE);
} else {
return new ResponseEntity(HttpStatus.FORBIDDEN);
}
}
}
#Service
public class LogoutService {
#Autowired
private AccountsRepository accountsRepository;
#Autowired
private MailService mailService;
#Autowired
private HashService hashService;
public AccountSignupEvent signupAccount(RequestAccountSignupEvent signupEvent) {
if (accountsRepository.existEmailAddress(signupEvent.getEmailAddress())) {
return AccountSignupEvent.duplicateEmailAddress();
}
Account newAccount = new Account();
newAccount.setCreated(new Date());
newAccount.setModified(new Date());
newAccount.setEmailAddress(signupEvent.getEmailAddress());
newAccount.setPassword(signupEvent.getPassword());
newAccount.setVerificationHash(hashService.getUniqueVerificationHash());
SignupMailEvent mailSentEvent = mailService.sendSignupMail(new RequestSignupMailEvent(newAccount));
if (!mailSentEvent.isMailSent()) {
return AccountSignupEvent.noMailSent();
}
Account persistedAccount = accountsRepository.persist(newAccount);
return AccountSignupEvent.accountCreated(persistedAccount);
}
public AccountLoginEvent loginAccount(RequestAccountLoginEvent loginEvent) {
if (accountsRepository.existLogin(loginEvent.getEmailAddress(), loginEvent.getPassword())) {
return AccountLoginEvent.granted();
}
return AccountLoginEvent.denied();
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = TestConfiguration.class)
#Transactional
#TransactionConfiguration(defaultRollback = true)
public class LogoutTest {
private MockMvc mockMvc;
#Autowired
private AccountCommandsController controller;
#Before
public void setup() {
mockMvc = standaloneSetup(controller).build();
}
#Test
public void signupNoMail() throws Exception {
doReturn(AccountSignupEvent.noMailSent()).when(service).signupAccount(any(RequestAccountSignupEvent.class));
// when(controller.service.signupAccount(any(RequestAccountSignupEvent.class))).thenReturn(AccountSignupEvent.noMailSent());
mockMvc.perform(post("/rest/signup")
.content(new Gson().toJson(new Account(UUID.randomUUID().toString(), UUID.randomUUID().toString())))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isServiceUnavailable());
}
}
I hope you see the problem. Every dependency works fine instead mailservice. I dont want to use #injectmock and #mock with MockitoAnnotations.initMocks(this); in my test file, because of the neccessary to provide for all dependencies mocks.
if your dependencies are running and you have a configuration class where you have defined the endpoint, you can use ConfigurableApplicationContext class, something like this:
public class test {
private static ConfigurableApplicationContext appContext;
private LogoutService service;
#AfterClass
public static void destroy() {
appContext.close();
}
#Before
public void setup() {
appContext = new AnnotationConfigApplicationContext(YourClassConfig.class);
service = appContext.getBean(LogoutService.class);
}
#Test
public void beansAreCreated() {
assertNotNull(service);
}
}
Or you can re-write your endpoint with a configuration class and you can use WireMock (http://wiremock.org) to emulate your dependency with real data, this should be something like this:
public class test {
#Rule
public WireMockRule wireMockRule = new WireMockRule(15000);
private static ConfigurableApplicationContext appContext;
private LogoutService service;
private static String serviceMockUrl;
#AfterClass
public static void destroy() {
appContext.close();
}
#Before
public void setup() {
serviceMockUrl = "http://localhost:" + wireMockRule.port();
appContext = new AnnotationConfigApplicationContext(TestConfig.class);
stubFor(get(urlEqualTo("urlToRequest")).
willReturn(aResponse().
withStatus(SC_OK).
withBody(createJsonArray("MapWithYourData").
withHeader("Content-Type", "application/json")));
service = appContext.getBean(LogoutService.class);
}
#Test
public void beansAreCreated() {
assertNotNull(service);
}
#Configuration
static class TestConfig {
#Bean
public PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertyPlaceholderConfigurer() {{
setProperties(new Properties() {{
setProperty("service.url", serviceMockUrl);
}});
}};
}
}
}
I hope this help you.
What you are trying to do is easily implemented using Spring Profiles.
On way to achieve it is the following:
#Configuration
public class TestConfiguration {
//this is the real mail service
#Bean
public MailService mailService() {
return new MailService(); //or whatever other bean creation logic you are using
}
//whatever else
}
#Configuration
#Profile("mockMail")
public class MockMailServiceConfig {
#Bean
#Primary
public MailService mockMailService() {
return mock(MailService.class);
}
}
Your test class would then look like:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = TestConfiguration.class)
#Transactional
#TransactionConfiguration(defaultRollback = true)
#ActiveProfiles("mockMail")
public class LogoutTest {
//do your testing
}
Note the use of #Primary in MockMailServiceConfig. I opted for this way since it wouldn't require you to introduce profiles anywhere else if you are not already using them. #Primary tells spring to use that specific bean if multiple candidates are available (in this case there is the real mail service and the mock service)

Categories

Resources