Test individual Spring Batch Tasklet step with parameters - unit-testing

I've implemented a simple job with 2 tasklets. I want to test the second tasklet by passing parameters.
I've read the Spring batch documentation and below my test:
#RunWith(SpringRunner.class)
#SpringBootTest
#ActiveProfiles({"test"})
#TestExecutionListeners( { DependencyInjectionTestExecutionListener.class,
StepScopeTestExecutionListener.class })
public class EtudeBatchApplicationTests {
#Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
public StepExecution getStepExecution() {
StepExecution execution = MetaDataInstanceFactory.createStepExecution();
execution.getJobExecution().getExecutionContext().putString("myValue", "foo,bar,spam");
return execution;
}
#Test
public void contextLoads() {
JobExecution jobExecution = jobLauncherTestUtils.launchStep("insertIncludedSiretsStep");
}
}
My problem is in my tasklet, the myValue is always null.
Below, the code of the tasklet:
#Component
#StepScope
#Slf4j
public class InsertIncludedSiretsTask implements Tasklet {
#Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
Object myValue = chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext().get("myValue");
log.info("INSERTINCLUDEDSIRETSTASK runnning");
Thread.sleep(3000);
return RepeatStatus.FINISHED;
}
}

You can mock the ChunkContext following this example :
http://www.javased.com/index.php?source_dir=spring-insight-plugins/collection-plugins/spring-batch/src/test/java/com/springsource/insight/plugin/springbatch/TaskletCollectionAspectTest.java
Here is my code :
public ChunkContext createChunkContext() {
StepExecution stepExecution=Mockito.mock(StepExecution.class);
StepContext stepContext=Mockito.mock(StepContext.class);
ChunkContext chunkContext=Mockito.mock(ChunkContext.class);
JobExecution jobExecution= createJobExecution();
Mockito.when(chunkContext.getStepContext()).thenReturn(stepContext);
Mockito.when(stepContext.getStepExecution()).thenReturn(stepExecution);
Mockito.when(stepExecution.getJobExecution()).thenReturn(jobExecution);
return chunkContext;
}
public JobExecution createJobExecution() {
JobExecution execution = MetaDataInstanceFactory.createJobExecution();
execution.getExecutionContext().putString("myValue", "foo,bar,spam");
return execution;
}
#Test
public void testSendEmail() throws Exception {
StepContribution contribution= Mockito.mock(StepContribution.class);
ChunkContext chunkContext= createChunkContext();
sendReportTasklet.execute(contribution, chunkContext );
}

Based on Melkior answer which helped me a lot I simplify the test:
public class MyTaskletTest {
private static final String MY_JOB_PARAM = "my.job.param";
#Mock
private StepContribution stepContribution;
#Mock
private StepExecution stepExecution;
#Mock
private StepContext stepContext;
#Mock
private ChunkContext chunkContext;
private MyTasklet tasklet;
#Before
public void setupTest() {
when(chunkContext.getStepContext()).thenReturn(stepContext);
when(stepContext.getStepExecution()).thenReturn(stepExecution);
}
#Override
public void init() {
tasklet = new MyTasklet();
}
#Test
public void should_test_my_tasklet() throws Exception {
when(stepExecution.getJobParameters()).thenReturn(defaultJobParameters("myParam"));
tasklet.execute(stepContribution, chunkContext);
}
private JobParameters defaultJobParameters(String myParam) {
JobParametersBuilder paramsBuilder = new JobParametersBuilder();
paramsBuilder.addString(MY_JOB_PARAM, myParam);
return paramsBuilder.toJobParameters();
}
}

Related

Junit java.lang.IllegalArgumentException: Could not resolve placeholder 'cors.origin.value' in value "${cors.origin.value}"

It is actually resolved but I will leave here solution if anyone will face the same issue. You have to configure placeholder manually like:
public EventControllerTest() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(eventController)
.addPlaceholderValue("cors.origin.value", "http://localhost:4200")
.build();
}
I am trying to perform simple unit test of some method from controller but I am facing an issue:
java.lang.IllegalArgumentException: Could not resolve placeholder 'cors.origin.value' in value "${cors.origin.value}"
Why is that happen? it is only simple unit test so I do not have to setup whole context for this right?
My code:
request I am calling is API_V1_EVENTS_FIND_BY_GENRE:
public class TestApiUrlStrings {
public static final String API_V1_EVENTS = "api/v1/events";
public static final String API_V1_EVENTS_FIND_BY_GENRE = API_V1_EVENTS + "/Dance?page=0";
}
Unit Test
public class EventControllerTest {
#Mock
EventService eventService;
#InjectMocks
EventController eventController;
MockMvc mockMvc;
public EventControllerTest() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(eventController)
.build();
}
#Test
public void findByGenre() throws Exception {
EventsDTO expected = EventsDTOdatasource.getEventsDTO();
when(eventService.findByGenre(anyString(),anyInt())).thenReturn(expected);
mockMvc.perform(get(TestApiUrlStrings.API_V1_EVENTS_FIND_BY_GENRE)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.events", hasSize(3)));
}
}
And controller
#Slf4j
#CrossOrigin(value = "${cors.origin.value}")
#RestController
#RequestMapping(EventController.API_V1_EVENTS)
public class EventController {
public static final String API_V1_EVENTS = "api/v1/events";
private final EventService eventService;
public EventController(EventService eventService) {
this.eventService = eventService;
}
#GetMapping("/{musicGenre}")
#ResponseStatus(HttpStatus.OK)
public EventsDTO findByGenre(#PathVariable String musicGenre,
#RequestParam(value = "page", defaultValue = "0") Integer pageNum) {
return eventService.findByGenre(musicGenre, pageNum);
}
#PutMapping
#ResponseStatus(HttpStatus.CREATED)
public EventsDTO saveAll(#RequestBody EventsDTO eventsDTO) {
return this.eventService.saveAll(eventsDTO);
}
}
Why exception is pointing to CORS value where I do not even need it here?
How to resolve this? There is not much about such exception anywhere.

Shared Preferences is null in mockito

I am trying to mock a simple shared preferences using Mockito . Since, the examples on google are too complicated to make anything out of it, I decided to go ahead on my own.
The shared preferences are setup using dagger.
It crashes with NPE in the saveString method in the SharedPreferenceManager class on the putString line.
#Module
public class StudentModule {
#Provides
#Singleton
static Context getContext(Application application) {
return application.getApplicationContext();
}
#Provides
#Singleton
static SharedPreferences getSharedPreferences(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context);
}
}
There is a manager class:
public class SharedPreferenceManager {
private SharedPreferences sharedPreferences;
private Context context;
#Inject public SharedPreferenceManager(SharedPreferences sharedPreferences, Context context){
this.sharedPreferences=sharedPreferences;
this.context=context;
}
public String doSomething(){
return sharedPreferences.getString("s","");
}
public void saveString(String s){
System.out.println(sharedPreferences.getClass().getSimpleName());
SharedPreferences.Editor editor=sharedPreferences.edit();
editor.putString("s","bis").apply();
}
}
Here is the test:
#RunWith(MockitoJUnitRunner.class)
public class MockTest {
#InjectMocks
SharedPreferenceManager sharedPreferenceManager;
#Mock SharedPreferences sharedPreferences;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void isSharedPefWorking(){
sharedPreferenceManager.saveString("bis");
assertEquals("bis",sharedPreferenceManager.doSomething());
}
}
SharedPreferences uses a SharedPreferences.Editor which you're not currently mocking.
You would need to do something like the following to mock and verify the behaviour of your SharedPreferenceManager.
#RunWith(MockitoJUnitRunner.class)
public class MockTest {
#InjectMocks
SharedPreferenceManager sharedPreferenceManager;
#Mock
SharedPreferences sharedPreferences;
#Mock
SharedPreferences.Editor sharedPreferencesEditor;
final String savedString = "savedString";
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
when(sharedPreferences.edit()).thenReturn(sharedPreferencesEditor);
when(sharedPreferencesEditor.putString(anyString(), anyString())).thenReturn(sharedPreferencesEditor);
}
#Test
public void saveString() {
sharedPreferenceManager.saveString(savedString);
verify(sharedPreferencesEditor).putString("s", savedString);
}
#Test
public void getString() {
when(sharedPreferences.getString("s","")).thenReturn(savedString);
String preferenceString = sharedPreferenceManager.doSomething();
assertEquals(preferenceString, savedString);
}
}

Unit testing RxJava in MVP presenter in android

I am new to TDD. Also new to MVP and Rxjava. I just dive into it and It is worth it. But I stuck at the testing part. I understand the basis of unit testing. It is a little bit difficult for me in beginning. But I stuck here and So how can test the presenter?
Here is the Presenter class -
public class NewsPresenter {
private final RxjavaService service;
private final MainView view;
private CompositeSubscription subscriptions;
public NewsPresenter(RxjavaService service, MainView view) {
this.service = service;
this.view = view;
subscriptions = new CompositeSubscription();
}
public void getNewsList(String urlQ){
view.showWait();
Subscription subscription = service.getNews(urlQ ,new RxjavaService.GetNewsCallback() {
#Override
public void onSuccess(Articles articles) {
view.removeWait();
view.getNewsListSuccess(articles);
}
#Override
public void onError(NetworkError networkError) {
view.removeWait();
view.onFailure(networkError.getAppErrorMessage());
Log.i("huh",networkError.getMessage());
}
});
subscriptions.add(subscription);
}
public void onStop(){
subscriptions.unsubscribe();
}
}
Here is the View Interface -
public interface MainView {
void showWait();
void removeWait();
void onFailure(String appErrorMessage);
void getNewsListSuccess(Articles articles);
}
Here is the RxJavaService class -
public class RxjavaService {
private final NewsRestService newsRestService;
public RxjavaService(NewsRestService newsRestService) {
this.newsRestService = newsRestService;
}
public interface GetNewsCallback {
void onSuccess(Articles articles);
void onError(NetworkError networkError);
}
public Subscription getNews(String q, final GetNewsCallback getNewsCallback) {
Log.i("stuck","service called");
return newsRestService.getNewsBySearch(q,"8dca7dea475e41e49518b2c61131e118",100)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.onErrorResumeNext(new Func1<Throwable, Observable<? extends Articles>>() {
#Override
public Observable<? extends Articles> call(Throwable throwable) {
return Observable.error(throwable);
}
})
.subscribe(new Subscriber<Articles>() {
#Override
public void onCompleted() {
Log.i("stuck","complete");
}
#Override
public void onError(Throwable e) {
getNewsCallback.onError(new NetworkError(e));
Log.i("stuck",e.getMessage());
}
#Override
public void onNext(Articles articles) {
getNewsCallback.onSuccess(articles);
Log.i("stuck","Onnext");
}
});
}
}
Here is the Test class where I am stuck-
#RunWith(MockitoJUnitRunner.class)
public class NewsListTest {
private NewsPresenter newsPresenter;
#Mock
private RxjavaService rxjavaService;
#Mock
private MainView mainView;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
newsPresenter = new NewsPresenter(rxjavaService,mainView);
}
#After
public void tearDown() throws Exception {
mainView = null;
newsPresenter.onStop();
}
#Test
public void Testing_The_Result() {
}
}
First things first
If you're into TDD, you'd never get into the situation you described. In TDD you start with a failing test, and just then go write the implementation. So your question is much more about testing then TDD.
I would recommend switching to RxJava2, as RxJava1 reaches End Of Life on March 31.
Look strange to me that RxJavaService changes the API from publish/subscribe to callbacks. Why not stick with rx API all the way to presenter?
Test with mocked RxJavaService
If you'd like to finish writing the test with the setup you have in the test, it would look something like this:
#Test
public void Testing_The_Result() {
final RxjavaService.GetNewsCallback[] callback = new RxjavaService.GetNewsCallback[1];
Mockito.when(rxjavaService.getNews(ArgumentMatchers.anyString(), ArgumentMatchers.any(RxjavaService.GetNewsCallback.class))).thenAnswer(new Answer<Subscription>() {
public Subscription answer(InvocationOnMock invocationOnMock) {
callback[0] = invocationOnMock.getArgument(1);
return mock(Subscription.class);
}
});
newsPresenter.getNewsList("some url");
Articles articles = new Articles();
callback[0].onSuccess(articles);
verify(mainView).removeWait();
verify(mainView).getNewsListSuccess(articles);
}
You can get rid of the ugly code by not using Mockito to mock RxJavaService, but rather roll you own hand-written mock, which would store the callback and provide it to the test.
However, I'd recommend a different approach.
Test with real RxJavaService and mocked NewsRestService
I'd say it makes more sense and gives a better test if we mocked only the NewsRestService:
#RunWith(MockitoJUnitRunner.class)
public class NewsList2Test {
private NewsPresenter newsPresenter;
#Mock
private MainView mainView;
#Mock
private NewsRestService newsRestService;
#Before
public void setUp() {
newsPresenter = new NewsPresenter(new RxjavaService(newsRestService), mainView);
}
#Test
public void show_success_in_view_when_there_are_articles() {
when(newsRestService.getNewsBySearch(eq("some url"), anyString(), anyInt()))
.thenReturn(Observable.just(new Articles()));
newsPresenter.getNewsList("some url");
verify(mainView).removeWait();
verify(mainView).getNewsListSuccess(any(Articles.class));
}
}

getExchange from mockEndPoint in a unit-test class for Camel Route Not Behaving As Expected

I want to getExchanges from a mockEndPoint in a unit-test class for Camel Route but it doesn't work.
Here is my unit test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:camel-unit-test.xml")
public class ImportDatabaseRouteTest extends CamelTestSupport {
#Value("${sql.importDatabase}")
String oldEndPoint;
#Autowired
private ImportDatabaseRoute importDatabaseRoute;
#Autowired
private DriverManagerDataSource dataSource;
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
return importDatabaseRoute;
}
#Before
public void mockEndpoints() throws Exception {
AdviceWithRouteBuilder adviceTest = new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
interceptSendToEndpoint(oldEndPoint)
.skipSendToOriginalEndpoint()
.to("mock:catchCSVList");
}
};
context.getRouteDefinitions().get(0).adviceWith(context, adviceTest);
}
#Override
public boolean isUseAdviceWith() {
return true;
}
#Override
protected JndiRegistry createRegistry() throws Exception {
JndiRegistry jndi = super.createRegistry();
//use jndi.bind to bind your beans
jndi.bind("dataSource", dataSource);
return jndi;
}
#Test
public void testTheImportRoute() throws Exception {
MockEndpoint mockEndPointTest = getMockEndpoint("mock:catchCSVList");
context.start();
List<List<String>> test = (List<List<String>>) mockEndPointTest.getExchanges().get(0).getIn().getBody();
assertEquals("4227",test.get(1).get(0));
assertEquals("370",test.get(1).get(1));
assertEquals("",test.get(1).get(2));
mockEndPointTest.expectedMessageCount(1);
mockEndPointTest.assertIsSatisfied();
context.stop();
}
}
And here are the results:
java.lang.ArrayIndexOutOfBoundsException: 0
at java.util.concurrent.CopyOnWriteArrayList.get(CopyOnWriteArrayList.java:387)
Please help me to fix it. Thank you so much.
You have to assert the mock before you get the exchanges. As those exchanges are the actual exchange that arrived at the mock. So its expectations has to be meet first, which says 1 message should arrive. And if that is success, then you can get that exchange via index 0, and you will not get an IndexOutOfBoundsException
MockEndpoint mockEndPointTest = getMockEndpoint("mock:catchCSVList");
context.start();
// set expectations on mock here
mockEndPointTest.expectedMessageCount(1);
mockEndPointTest.assertIsSatisfied();
// okay now we can get the exchange's from the mock
List<List<String>> test = (List<List<String>>) mockEndPointTest.getExchanges().get(0).getIn().getBody();
assertEquals("4227",test.get(1).get(0));
assertEquals("370",test.get(1).get(1));
assertEquals("",test.get(1).get(2));
context.stop();

how to mock apache-camel EL

i have the following RouteBuilder.
public class MyRoute extends RouteBuilder {
#Override
public void configure() {
errorHandler(deadLetterChannel(errorHandlerEndpoint)
.maximumRedeliveries(1)
.redeliveryDelay(2000)
.retryAttemptedLogLevel(LoggingLevel.WARN));
from(fromEndpoint).routeId("fetchPreprocessingResultFromMarklogicRoute")
.setHeader("principal").method(principalService, "getPrincipal").id("getPrincipalServiceMethod") // put principal to header for latter use
.multicast()
.filter(xpath("//files[#ml-generated='true']"))
.choice()
.when(PredicateBuilder.isEqualTo(constant(EPrincipal.VETCENTER.principal()), simple("${header.principal.principal.principal}")))
.log("Sending VetCenter preprocessing report...")
.inOnly(toVetCenterEmailNotificationEndpoint)
.when(PredicateBuilder.isEqualTo(constant(EPrincipal.OSTEOTHEK.principal()), simple("${header.principal.principal.principal}")))
.log("Sending Osteothek preprocessing report...")
.inOnly(toOsteothekEmailNotificationEndpoint)
.otherwise()
.log("Principal unknown. Don't sending a preprocessing report...")
.inOnly("direct:trash") // #ToDo: Write test
.end()
.inOnly(toCleaningPhaseDecisionEndpoint)
.inOnly(deleteImportDirsEndpoint)
.end();
}
}
This is the JUnit-Test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:application-context-test.xml"})
public class FetchPreprocessingResultFromMarklogicRoute_Test extends CamelTestSupport{
private RouteBuilder route;
#Value("${fetchPreprocessingResultFromMarklogicRoute.fromEndpoint}")
private String testFromEndpoint;
#Value("${fetchPreprocessingResultFromMarklogicRoute.toCleaningPhaseDecisionEndpoint}")
private String toCleaningPhaseDecisionEndpoint;
#Value("${fetchPreprocessingResultFromMarklogicRoute.vetcenter.toEmailNotificationEndpoint}")
private String toEmailNotificationVetCenterEndpoint;
#Value("${fetchPreprocessingResultFromMarklogicRoute.osteothek.toEmailNotificationEndpoint}")
private String toEmailNotificationOsteothekEndpoint;
#Value("${fetchPreprocessingResultFromMarklogicRoute.deleteImportDirsEndpoint}")
private String testDeleteImportDirsEndpoint;
#Value("${fetchPreprocessingResultFromMarklogicRoute.errorHandlerEndpoint}")
private String testErrorHandlerEndpoint;
private MockEndpoint emailNotificationVetCenterMOCKEndpoint;
#Mock
private PrincipalService principalServiceMOCK;
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
if(route == null){
route = new MyRoute(
testFromEndpoint,
toCleaningPhaseDecisionEndpoint,
toEmailNotificationVetCenterEndpoint,
toEmailNotificationOsteothekEndpoint,
testDeleteImportDirsEndpoint,
testErrorHandlerEndpoint,
principalServiceMOCK);
}
return route;
}
#Override
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
Principal principal = new Principal();
principal.setPrincipal(EPrincipal.VETCENTER);
Mockito.when(principalServiceMOCK.getPrincipal("anyIdentificator")).thenReturn(principal);
super.setUp();
}
#Test
public void test() throws InterruptedException{
InputStream resourceInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("testdata/importreport/inc/import-log-Vetcenter.xml");
String message = new Scanner(resourceInputStream).useDelimiter("\\A").next();
emailNotificationVetCenterMOCKEndpoint = getMockEndpoint(toEmailNotificationVetCenterEndpoint);
emailNotificationVetCenterMOCKEndpoint.expectedBodiesReceived(message);
// Herausforderung ist, die Datei aus dem Verzeichnis ablesen und camel Regeln zu prüfen
template.sendBody(testFromEndpoint, message);
emailNotificationVetCenterMOCKEndpoint.assertIsSatisfied();
}
}
this is the snippet of Principal and enum EPrincipal:
public class Principal {
private EPrincipal principal;
public EPrincipal getPrincipal() {
return principal;
}
public void setPrincipal(EPrincipal principal) {
this.principal = principal;
}
}
public enum EPrincipal {
VETCENTER("Vetcenter"), OSTEOTHEK("Osteothek");
private final String principal;
EPrincipal(final String principal)
{
this.principal = principal;
}
public String principal()
{
return principal;
}
}
i don't know how to make a mock for this snippet:
.when(PredicateBuilder.isEqualTo(constant(EPrincipal.VETCENTER.principal()), simple("${header.principal.principal.principal}")))
more exact for this part:
simple("${header.principal.principal.principal}")
It is expression language and i have no idiea how to create a mock for it. Is there other solution to create a unit test for it?
very many thanks for help
Force principalServiceMOCK to return your desired test principal in getPrincipal.
Have a look at the following simplified example.
Interface:
public static interface PrincipalService {
Principal getPrincipal(String id);
Principal getPrincipal();
}
Test class:
#Mock
PrincipalService principalServiceMOCK;
#EndpointInject(uri = "mock:result")
MockEndpoint resultEndpoint;
#Override
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
Principal principal = new Principal();
principal.setPrincipal(Type.VETCENTER);
Mockito.when(principalServiceMOCK.getPrincipal(TEST_ID)).thenReturn(principal);
Mockito.when(principalServiceMOCK.getPrincipal()).thenReturn(principal);
super.setUp();
}
#Test
public void test() throws InterruptedException {
resultEndpoint.expectedMessageCount(1);
resultEndpoint.expectedBodiesReceived(TEST_ID); // OK
resultEndpoint.expectedHeaderReceived("principal1", Type.VETCENTER);
resultEndpoint.expectedHeaderReceived("principal2", Type.VETCENTER);
template.sendBody("direct:start", TEST_ID);
resultEndpoint.assertIsSatisfied();
}
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() {
from("direct:start")
.setHeader("principal1").method(principalServiceMOCK, "getPrincipal(${body}).getPrincipal()")
.setHeader("principal2").method(principalServiceMOCK, "getPrincipal().getPrincipal()")
.to("mock:result");
}
};
}
Please note that:
if using the original service implementation and constant then the header is evaluated at configuration time (= configure() is invoked) and if using method at runtime (= direct:start is invoked).
if using the mock service then the header is evaluated at configuration time for both cases.