How can I test programmatically created #Scheduled method? - java

I've seen lots of guides on how to test a #Scheduled bean. But what if I create it programmatically?
I am creating a scheduled job( goodBoy.bark() ) that will run every 5 seconds. This is pretty much the equivalent of #Scheduler annotation.
#EnableScheduling
public class DogScheduler implements SchedulingConfigurer {
private final Dog goodBoy;
#Autowired
public DogScheduler(Dog goodBoy){
this.goodBoy= goodBoy;
}
#Bean
public Executor taskExecutor() {
return Executors.newSingleThreadScheduledExecutor();
}
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
taskRegistrar.addTriggerTask(
goodBoy::bark,
context -> {
Optional<Date> lastCompletionTime =
Optional.ofNullable(context.lastCompletionTime());
Instant nextExecutionTime =
lastCompletionTime.orElseGet(Date::new).toInstant()
.plusSeconds(5);
return Date.from(nextExecutionTime);
}
);
}
}
#Component
public class Dog {
private Food meat;
#Autowired
public DomainRefreshScheduler(Food meat){
this.meat= meat;
}
public void bark(){
log.warn("woof!");
}
}
How can I test goodBoy.bark() method? I would like for example, to start the application, wait for 10 seconds and then verify that goodBoy.bark() was called 2 times.

Related

In Spring MVC 4 i am getting Quartz Scheduler run Twice at a time

In My Spring MVC project have, A Quartz Scheduler Which Will Run Twice at a time how to i fixed it and Get One Execution at a time.
where my web Initializer class is,
#WebListener
public class QuartzListener extends QuartzInitializerListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
super.contextInitialized(sce);
ServletContext ctx = sce.getServletContext();
StdSchedulerFactory factory = (StdSchedulerFactory) ctx.getAttribute(QUARTZ_FACTORY_KEY);
try {
Scheduler scheduler = factory.getScheduler();
JobDetail jobDetail = JobBuilder.newJob(TestJob.class).build();
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("simple").withSchedule(
CronScheduleBuilder.cronSchedule("0 0/1 * 1/1 * ? *")).startNow().build();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
} catch (Exception e) {
ctx.log("There was an error scheduling the job.", e);
}
}
}
And Test Class,
public class TestJob implements Job {
#Override
public void execute(final JobExecutionContext ctx) throws
JobExecutionException {
System.out.println("Executing Job");
}
}
and web Initializer Class like,
public class WebAppInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer{
#Override
protected Class<?>[] getRootConfigClasses(){
return new Class[]{WebSecurityConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses(){
return new Class[]{WebAppConfig.class, HibernateConfiguration.class};
}
#Override
protected String[] getServletMappings(){
return new String[]{"/"};
}
}
and my WebConfig is,
#Configuration
#EnableWebMvc
#ComponentScan(basePackages="com.neron")
public class WebAppConfig extends WebMvcConfigurerAdapter {
#Bean
public ViewResolver resourceViewResolver(){
ResourceBundleViewResolver viewResolver = new
ResourceBundleViewResolver();
viewResolver.setOrder(0);
viewResolver.setBasename("views");
return viewResolver;
}
............
...............
#Scheduled(cron = "0 0/1 * 1/1 * ?")
public void schedulerCall()
{
System.out.println("Calling");
}
Here i get two times of "Executing Job" every minute, but i want only once
"Executing Job" at every minute.
can any one solve it ? Thanks In Advance!
Here your solution
add this annotation on the top of job class
import org.quartz.DisallowConcurrentExecution;// import this
#DisallowConcurrentExecution
if you're working on cluster environment then different implementation. if you need comment here. or if your problem solved then accept it.
More information find GitHub link https://github.com/faizakram/Spring_Base_Exmaple_Annotation_Based
//Configuration class
#Configuration
#EnableWebMvc
#EnableScheduling
#ComponentScan(basePackages = { CommonConstants.BASE_PACKAGE })
public class WebMvcConfig {
}
//create a service method like this
#Scheduled(cron = "0 0/1 * 1/1 * ?")
public void schedulerCall()
{
System.out.println("Calling");
}

What is a common pattern for scheduled event handling in Spring?

In my application I need to add scheduled event checking and handling. When some business logic happened I need to create a posponed trigger, which should fire some actions through a particular time gap. For example:
If user posted photo, he should be notified if there is no likes under it within three days.
I feel that it should be a common pattern for such activities, relied on Spring framework features.
In your main config you need some like :
#Configuration
#EnableScheduling
public class HelloWorldConfig { ..}
Then in you bean where you want to schedule something :
#Scheduled(fixedRate=1000)
public void reload() { ..}
See http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html
Make sure you include the #EnableScheduling or equivalent if you're using XML config.
#Component
public class DemoExpirationEvent implements Runnable {
#Resource(name = "demoPhotoService")
private DemoExpirationService demoExpirationService;
#Resource(name = "demoExpirationTaskScheduler")
private TaskScheduler taskScheduler;
private Long id;
#Override
public void run() {
demoExpirationService.expiration(id);
}
public void schedule(Long id, Date dateToExpire){
this.id = id;
taskScheduler.schedule(this, dateToExpire);
}
}
#Service("demoPhotoService")
public class DemoPhotoServiceImpl implements DemoExpirationService, DemoPhotoService {
#Override
public void expiration(Long id) {
DemoPhoto photo = getPhoto(id);
photo.setExpirationDate(null);
savePhoto(photo);
notifyAuthorOfPhoto(id);
}
#Override
public void getPhoto(long id){
//some implementation
}
#Override
public void savePhoto(DemoPhoto photo){
//some implementation
}
#Override
public void notifyAuthorOfPhoto(long id){
//some implementation
}
}
public class DemoAddedPhotoActivity {
#Resource(name = "demoExpirationEvent")
private DemoExpirationEvent demoExpirationEvent;
#Resource(name = "demoPhotoService")
private DemoPhotoService demoPhotoService;
public void execute(long id) throws Exception {
DemoPhoto photo = demoPhotoService.getPhoto(id);
Date expirationDate = new Date(System.currentTimeMillis() + 30000000000L);
photo.setExpirationDate(expirationDate);
demoPhotoService.savePhoto(photo);
demoExpirationEvent.schedule(id, expirationDate);
}
}
register task scheduler in your applicationContext.xml
<beans xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-4.1.xsd">
<task:scheduler id="demoExpirationTaskScheduler" pool-size="3"/>
And rest of beans too and call activity on adding photo (it can be controller method with execute like method

Spring Boot - Alternative to Time.schedule?

I want to do something like javascript's setInterval(function, interval)/setTimeout(function, timeout) in Spring Boot.
I found the #Scheduled annotation that has the fixedRate argument, but as an annotation I cannot change the rate dynamically (Or can I?)
For now I am using java.util.Timer, but I would rather use Spring. Is there a way?
Can I get a Scheduler instance and work with it dynamically?
thanks!
You may use a Trigger which lets you dynamically control the next execution. You need to implement SchedulingConfigurer, another answer covers exactly this:
Scheduling a job with Spring programmatically (with fixedRate set dynamically)
EDIT to answer comments:
nextExecutionTime is called on and on and on... The next time the task (and nextExecutionTime) is called is defined by this:
nextExecutionTime.setTime(lastActualExecutionTime != null ? lastActualExecutionTime : new Date());
nextExecutionTime.add(Calendar.MILLISECOND, numberOfMillisecondsBeforeCallingTheTask);
All you need to do is have this numberOfMillisecondsBeforeCallingTheTask value changed.
Example:
#RestController
public class MyController {
public static int triggerDelay = 1000;
#RequestMapping("/changetrigger/{val}")
public void test(#PathVariable int val){
this.triggerDelay = val;
}
}
#SpringBootApplication
#EnableScheduling
public class Launcher implements SchedulingConfigurer{
public static void main(String[] args){
new SpringApplicationBuilder() //
.sources(Launcher.class)//
.run(args);
}
#Bean(destroyMethod = "shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(100);
}
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
;
taskRegistrar.addTriggerTask(new TriggerTask(new Runnable() {
#Override
public void run() {
System.out.println("blah");
System.out.println(System.currentTimeMillis());
}
}, new Trigger() {
#Override
public Date nextExecutionTime(TriggerContext triggerContext) {
Calendar nextExecutionTime = new GregorianCalendar();
nextExecutionTime.setTime(new Date());
nextExecutionTime.add(Calendar.MILLISECOND, MyController.triggerDelay);
System.out.println(System.currentTimeMillis());
return nextExecutionTime.getTime();
}}));
}
}
Notice how the dynamic value MyController.triggerDelay is used for the next execution. So if you change the number, the next execution time will be changed. You'll see if you put a breakpoint inside nextExecutionTime.
You can use #Scheduled(fixedRateString = "${spring.boot.schedule.rate}") for your case, where the spring.boot.schedule.rate is the external properties in application.properties
spring.boot.schedule.rate=5000
Misunderstand the question, above is just the externalize the properties.
For the dynamic solution, maybe this should be work, using the spEL in the annonation:
#Service
public class ScheduledService {
#Autowired
private FixRateProperty fixRateProperty;
#Scheduled(fixedRateString = "#{fixRateProperty.fixRate}")
private void reportCurrentTime() {
System.out.println(new Date());;
}
}
This is the FixRateProperty
#Component
public class FixRateProperty {
private Long fixRate = 500L;
public Long getFixRate() {
return fixRate;
}
public void setFixRate(Long fixRate) {
this.fixRate = fixRate;
}
}
so you can externalize the rate in the properties or set the fixRate somewhere.
Found a solution that works for my case.
In Main.java:
#SpringBootApplication
#ConfigurationProperties
#EnableScheduling
public class Main {
#Bean
ThreadPoolTaskScheduler taskScheduler() {
return new ThreadPoolTaskScheduler();
}
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
In Service.java (Called from a rest controller):
#Service
public class Service {
private static final Logger log = LoggerFactory.getLogger(Service.class);
private final TaskScheduler scheduler;
#Autowired
public Service(TaskScheduler scheduler) {
this.scheduler = scheduler;
}
public void startTask(int inteval) {
scheduler.schedule(() -> log.info("Doing work"), triggerContext -> {
if (some_condition) {
ZonedDateTime now = ZonedDateTime.now();
return Date.from(now.plusSeconds(interval).toInstant());
} else {
// Stop the execution
return null;
}
});
}
}
This solution works, but I'm not sure it is the correct way.
You are welcome to comment below, and I might change the solution if I get a suggestion I find helpful.

How to combine Mockito and Spring in TestNG

We are building an application which uses Spring Boot. We write unit tests using TestNG and Mockito. However I find it pretty annoying to write when(...) configuration, I would like to use real components instead. I started to use #Spy components instead of mocks and this works pretty well until I need to put a Spy into a Spy. I'd like to avoid loading a Spring Context if possible, because creation of the context is very slow it looks like overkill for me to load it for at max 5 classes.
Is there any way, how could I use real code instead of Mocks and not loading whole Spring context? Or is my approach wrong at all and I should mock out all other classes then the tested one?
The other way to do this and may take some modifying of code on your end is to do it by constructor injection instead of field injection. Basically taking away any need of the spring context for testing. so the same from the other answer
Class to test
#Service
public class RecordServiceImpl implements RecordService
{
private final RecordRepository recordRepository;
#Autowired
public RecordServiceImpl(RecordRepository recordRepository)
{
this.recordRepository = recordRepository;
}
public Record find(String id)
{
return recordRepository.findOne(id);
}
public List<Record> findAll()
{
return recordRepository.findAll();
}
#Transactional
public Record save(Record record)
{
record.setRecordStatus("F");
return recordRepository.save(record);
}
}
Test Case
//#RunWith(SpringJUnit4ClassRunner.class)
//#ContextConfiguration(classes = {RecordServiceTestConfig.class})
public class RecordServiceTest
{
// #Autowired
private RecordRepository recordRepository = Mockito.mock(RecordRepository.class);
// #Autowired
private RecordService recordService;
#Before
public void setup()
{
Mockito.reset(recordRepository);
recordService = new RecordServiceImpl(recordRepository);
}
#Test
public void testFind()
{
Mockito.when(recordRepository.findOne(Mockito.anyString())).thenReturn(null);
Record record = recordService.find("1");
Assert.assertNull(record);
Mockito.verify(recordRepository, Mockito.times(1)).findOne(Mockito.eq("1"));
}
#Test
public void testSave()
{
Mockito.when(recordRepository.save(Mockito.any(Record.class)))
.thenAnswer(new Answer<Record>()
{
#Override
public Record answer(InvocationOnMock invocation) throws Throwable
{
Record record = (Record) invocation.getArguments()[0];
Assert.assertEquals("F", record.getRecordStatus());
return record;
}
});
Record record = new Record();
record = recordService.save(record);
Assert.assertNotNull(record);
Mockito.verify(recordRepository, Mockito.times(1)).save(Mockito.eq(record));
}
#Test
public void findAll()
{
Mockito.when(recordRepository.findAll()).thenReturn(new ArrayList<Record>());
List<Record> records = recordService.findAll();
Assert.assertNotNull(records);
Assert.assertEquals(0, records.size());
Mockito.verify(recordRepository, Mockito.times(1)).findAll();
}
}
I think your looking for like this with the use of #ContextConfiguration and #Configuration
Class to test
#Service
public class RecordServiceImpl implements RecordService
{
#Autowired
private RecordRepository recordRepository;
public Record find(String id)
{
return recordRepository.findOne(id);
}
public List<Record> findAll()
{
return recordRepository.findAll();
}
#Transactional
public Record save(Record record)
{
record.setRecordStatus("F");
return recordRepository.save(record);
}
}
Test Class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {RecordServiceTestConfig.class})
public class RecordServiceTest
{
#Autowired
private RecordRepository recordRepository;
#Autowired
private RecordService recordService;
#Before
public void setup()
{
Mockito.reset(recordRepository);
}
#Test
public void testFind()
{
Mockito.when(recordRepository.findOne(Mockito.anyString())).thenReturn(null);
Record record = recordService.find("1");
Assert.assertNull(record);
Mockito.verify(recordRepository, Mockito.times(1)).findOne(Mockito.eq("1"));
}
#Test
public void testSave()
{
Mockito.when(recordRepository.save(Mockito.any(Record.class)))
.thenAnswer(new Answer<Record>()
{
#Override
public Record answer(InvocationOnMock invocation) throws Throwable
{
Record record = (Record) invocation.getArguments()[0];
Assert.assertEquals("F", record.getRecordStatus());
return record;
}
});
Record record = new Record();
record = recordService.save(record);
Assert.assertNotNull(record);
Mockito.verify(recordRepository, Mockito.times(1)).save(Mockito.eq(record));
}
#Test
public void findAll()
{
Mockito.when(recordRepository.findAll()).thenReturn(new ArrayList<Record>());
List<Record> records = recordService.findAll();
Assert.assertNotNull(records);
Assert.assertEquals(0, records.size());
Mockito.verify(recordRepository, Mockito.times(1)).findAll();
}
}
Test Class Configuration
#Configuration
public class RecordServiceTestConfig
{
#Bean
public RecordService recordService()
{
return new RecordServiceImpl();
}
#Bean
public RecordRepository recordRepository()
{
return Mockito.mock(RecordRepository.class);
}
}
the entire test class took 714ms to run the findAll test took 1ms.
If you are looking to configure your testcase using testng with Spring then you to mention
#ContextConfiguration(locations={
"/context.xml","/test-context.xml"})
at class level to load you spring file and extends your class org.springframework.test.context.testng.AbstractTestNGSpringContextTests
Sample
https://dzone.com/articles/spring-testing-support-testng

Spring #Async method inside a Service

I have this service bean with a sync method calling the internal async method:
#Service
public class MyService {
public worker() {
asyncJob();
}
#Async
void asyncJob() {
...
}
}
The trouble is that the asyncJob is not really called in async way.
I found that this doesn't work because an internal call skips the AOP proxy.
So I try to self-refer the bean:
#Service
public class MyService {
MyService mySelf;
#Autowired
ApplicationContext cnt;
#PostConstruct
public void init() {
mySelf=(MyService)cnt.getBean("myService");
}
public void worker() {
mySelf.asyncJob();
}
#Async
void asyncJob() {
...
}
}
It fails. Again no async call.
So I tried to divide it in two beans:
#Service
public class MyService {
#Autowired
MyAsyncService myAsyncService;
public void worker() {
myAsyncService.asyncJob();
}
}
#Service
public class MyAsyncService {
#Async
void asyncJob() {
...
}
}
Fails again.
The only working way is to call it from a Controller Bean:
#Controller
public class MyController {
#Autowired
MyAsyncService myAsyncService;
#RequestMapping("/test")
public void worker() {
myAsyncService.asyncJob();
}
}
#Service
public class MyAsyncService {
#Async
public void asyncJob() {
...
}
}
But in this case it is a service job. Why I cannot call it from a service?
Found a really nice way to solve this (with java8) in the case where you have a lot of various things you want to both sync and async. Instead of creating a separate XXXAsync service for each 'synchronous' service, create a generic async service wrapper:
#Service
public class AsyncService {
#Async
public void run(final Runnable runnable) {
runnable.run();
}
}
and then use it as such:
#Service
public class MyService {
#Autowired
private AsyncService asyncService;
public void refreshAsync() {
asyncService.run(this::refresh);
}
public void refresh() {
// my business logic
}
public void refreshWithParamsAsync(String param1, Integer param2) {
asyncService.run(() -> this.refreshWithParams(param1, param2));
}
public void refreshWithParams(String param1, Integer param2) {
// my business logic with parameters
}
}
I solved the third method (divide it in two beans) changing the async method's access modifier to public:
#Service
public class MyService {
#Autowired
MyAsyncService myAsyncService;
public void worker() {
myAsyncService.asyncJob();
}
}
#Service
public class MyAsyncService {
#Async
public void asyncJob() { // switched to public
...
}
}
In my case, it was easier to remove the #Async annotation and use the taskExecutor directly to submit my task:
Before
#Async("taskExecutor")
private Future<U> executerEnAsync(
final T pInput) {
final U resultat = this.appelerBS(pInput);
return new AsyncResult<U>(resultat);
}
After
#Autowired
private AsyncTaskExecutor taskExecutor;
private Future<U> executerEnAsync(
final T pInput) {
final Future<U> future = taskExecutor.submit(new Callable<U>() {
#Override
public U call() {
final U resultat = appelerBS(pInput);
return resultat;
}
});
return future;
}

Categories