Iam trying to mock switchyard endpoint switchyard://TohpGetAccountReports using the mock endpoint in camel. the mockAccountReportEndpoint defined in junit test is returning null and the test id failing with nullpointer exception.can you please tell me what is wrong with my code?
Camel route :
<route id="accountReportRoute" streamCache="true">
<from uri="direct:accountReport" />
<doTry>
<setProperty propertyName="hpResponse">
<constant>A</constant>
</setProperty>
<to
uri="xslt:xslt/account_reports_manager/create_get_accountreport_request.xslt" />
<log message="GetAccountReports Request : ${body}" logName="esb.hp.InModelProvider.AccountReport"
loggingLevel="TRACE" />
<to
id="AccountReportEndpoint" uri="switchyard://TohpGetAccountReports?operationName=GetAccountReports" />
<log message="GetAccountReports Response : ${body}" logName="esb.hp.InModelProvider.AccountReport"
loggingLevel="TRACE" />
<to
uri="xslt:xslt/account_reports_manager/create_get_accountreport_response.xslt" />
<doCatch>
<exception>java.lang.Exception</exception>
<handled>
<constant>false</constant>
</handled>
<log
message="Exception in hp Model provider accountReportRoute ${exception.stacktrace} "
logName="esb.hp.InModelProvider.AccountReport" loggingLevel="ERROR" />
</doCatch>
</doTry>
<log message="Workaround for handling account report soap fault"
logName="esb.hp.InModelProvider.AccountReport" loggingLevel="DEBUG" />
</route>
junit test class
package com.company.esb.hp.in.modelprovider.test;
import java.util.Map;
import org.apache.camel.CamelContext;
import org.apache.camel.EndpointInject;
import org.apache.camel.Exchange;
import org.apache.camel.Expression;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.AdviceWithRouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.impl.DefaultExchange;
import org.apache.camel.model.ModelCamelContext;
import org.apache.log4j.Logger;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.switchyard.ServiceDomain;
import org.switchyard.component.test.mixins.cdi.CDIMixIn;
import org.switchyard.component.test.mixins.http.HTTPMixIn;
import org.switchyard.test.BeforeDeploy;
import org.switchyard.test.Invoker;
import org.switchyard.test.ServiceOperation;
import org.switchyard.test.SwitchYardRunner;
import org.switchyard.test.SwitchYardTestCaseConfig;
import org.switchyard.test.SwitchYardTestKit;
import org.switchyard.transform.config.model.TransfohpwitchYardScanner;
import com.company.esb.common.test.esbSwitchyardTest;
import com.company.esb.hp.in.modelprovider.test.util.RiskInProviderUtil;
#SwitchYardTestCaseConfig(config = SwitchYardTestCaseConfig.SWITCHYARD_XML, mixins = {
CDIMixIn.class, HTTPMixIn.class }, scanners = { TransfohpwitchYardScanner.class })
#RunWith(SwitchYardRunner.class)
public class hpInModelProviderTest extends esbSwitchyardTest {
private static final Logger LOG = Logger
.getLogger(hpInModelProviderTest.class);
private SwitchYardTestKit testKit;
public static final String getAcctResult = "TohpGetAccountReports";
#EndpointInject(uri = "mock://switchyard:TohpGetAccountReports*")
protected MockEndpoint mockAccountReportEndpoint;
#BeforeDeploy
public void setProperties() {
System.setProperty("esb.hp.inmodelprovider.url", "http://pusslasrws1451.company.biz");
}
#Before
public void installServices() {
simulateesbServices(testKit);
}
#Test
public void testAccountReportDirectRouteSuccess() throws Exception {
String request = readFile("xml/endtoend/success/GetJobsResults/get_job_status-response.xml");
ServiceDomain domain = testKit.getServiceDomain();
//testKit.removeService(getAcctResult);
//testKit.registerInOutService(getAcctResult,
// new GetAccountReportsServiceMockExchangeHandler());
CamelContext ctx = (CamelContext) domain
.getProperty("CamelContextProperty");
Exchange ex = new DefaultExchange(ctx);
ModelCamelContext modelContext = (ModelCamelContext) ctx;
modelContext.getRouteDefinition("accountReportRoute").adviceWith(modelContext, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
weaveById("AccountReportEndpoint").replace().to(mockAccountReportEndpoint);
}
});
mockAccountReportEndpoint.expectedMessageCount(1);
mockAccountReportEndpoint.returnReplyBody(new Expression() {
#Override
public <T> T evaluate(Exchange exchange, Class<T> type) {
return exchange.getContext().getTypeConverter().convertTo(type, RiskInProviderUtil.readFile("xml/endtoend/success/GetJobsResults/get_account_report_service-response.xml"));
}
});
// MockEndpoint endpoint = getMockEndpoint("mock:switchyard:service");
ex.setProperty("sToken", "f3669d3a-5a2b-4b99-a8df-3aabfd4aae58");
ex.setProperty("sAccId", "196497");
ex.getIn().setBody(request);
ProducerTemplate producer = ctx.createProducerTemplate();
producer.send("direct:accountReport", ex);
System.out.println(ex.getIn().getBody(String.class));
}
#Override
protected void addSetupProperties(Map<String, String> map) {
}
}
..after you have done the adviceWith you must start CamelContext by invoke the start method on the context instance.
http://camel.apache.org/advicewith.html#AdviceWith-UsingisUseAdviceWith()
Try to override the isUseAdviceWith() method (should return true) and start the context after you have done the adviceWith. If it has been already started then try to stop() it and start() it again (cold restart).
Related
Since i am new to Mockito and AEM model java. I have a gone through some docs and wrote my first Mockito file for AEM Model java. In my code i've not see any errors, but while running i am not getting success and can't complete the code coverage 100%. Can anyone correct/help me to fix my code[given sample java with respective mockito file]
Java File:
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.SlingObject;
import org.json.JSONException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.abc.cc.ddd.ResourceResolverService;
import com.abc.cc.ddd.services.models.bean.Accordion;
#Model(adaptables = SlingHttpServletRequest.class)
public class AccordionModel {
private final static Logger log = LoggerFactory.getLogger(AccordionModel.class);
#SlingObject
private SlingHttpServletRequest request;
#Inject
public ResourceResolverService resolverService;
private Resource resource;
public List < Accordion > accordionList = new ArrayList < Accordion > ();
#PostConstruct
protected void init() throws LoginException, JSONException {
log.info("AccordionModel init method Start");
resource = request.getResource();
final ValueMap configurationOptionProperties = resource.getValueMap();
log.debug("iconfigurationOptionProperties is " + configurationOptionProperties);
String count = configurationOptionProperties.get("count", String.class);
if (count != null) {
for (int i = 1; i <= Integer.valueOf(count); i++) {
Accordion accordion = new Accordion();
String title = configurationOptionProperties.get("title" + i, String.class);
String rte = configurationOptionProperties.get("rte" + i, String.class);
accordion.setTitle(title);
accordion.setRte(rte);
accordionList.add(accordion);
}
}
log.info("AccordionModel init method End");
}
public List < Accordion > getAccordionList() {
return accordionList;
}
}
Mockito code
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.List;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import org.json.JSONException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import com.abc.cc.ddd.ResourceResolverService;
import com.abc.cc.ddd.services.models.bean.Accordion;
#RunWith(MockitoJUnitRunner.class)
public class AccordionModelTest {
#InjectMocks
private AccordionModel accordionModel;
#Mock
Resource resource;
#Mock
SlingHttpServletRequest request;
#Mock
ResourceResolverService resourceResolverService;
#Mock
ValueMap valuemap;
public List < Accordion > accordionList = new ArrayList < Accordion > ();
String count = "6";
//max count, based on this count loop execute and get/set into the list
#Before
public void setUp() throws Exception {
when(request.getResource()).thenReturn(resource);
when(resource.getValueMap()).thenReturn(valuemap);
}
#Test
public void shouldReturnNullWhenPropertyIsNull() throws LoginException, JSONException {
when(valuemap.get("count", String.class)).thenReturn(null);
accordionModel.init();
assertEquals(accordionModel.getAccordionList(), null);
}
#Test
public void shouldReturnWhenPropertyNotNull() throws LoginException, JSONException {
when(valuemap.get("count", String.class)).thenReturn("count");
accordionModel.init();
assertEquals(accordionModel.getAccordionList(), count);
}
}
Errors in program its showing line--> accordionModel.init();
java.lang.NumberFormatException: For input string: "count"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.valueOf(Unknown Source)
at com..services.sling.models.AccordionModel.init(AccordionModel.java:44) at
com..services.sling.models.AccordionModelTest.
shouldReturnWhenPropertyNotNull(AccordionModelTest.java:55)
java.lang.AssertionError: expected:<[]> but was:<null>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:834)
at org.junit.Assert.assertEquals(Assert.java:118)
at org.junit.Assert.assertEquals(Assert.java:144)
at com..services.sling.models.AccordionModelTest.
shouldReturnNullWhenPropertyIsNull(AccordionModelTest.java:53)
java.lang.AssertionError: expected:<[]> but was:<null>
If you return null your list is empty. So adjust your test.
Consider renaming the method name as well.
If thats not what you want, you'll need to change your implementation.
#Test
public void shouldReturnNullWhenPropertyIsNull() throws LoginException, JSONException {
when(valuemap.get("count", String.class)).thenReturn(null);
accordionModel.init();
assertTrue(accordionModel.getAccordionList().isEmpty());
}
java.lang.NumberFormatException: For input string: "count"
"count" can not be converted into an Integer. Try using your count variable ("6") instead.
You should check the content of the list, for now I adjusted it to check that the list has the correct size.
#Test
public void shouldReturnWhenPropertyNotNull() throws LoginException, JSONException {
when(valuemap.get("count", String.class)).thenReturn(count);
accordionModel.init();
assertEquals(Integer.valueOf(count), accordionModel.getAccordionList().size());
}
Note that generally the parameter order for assert's should be expected vs actual.
I have a service project written in Java11. It is using junit tests to cover full code coverage.
I have written scheduler method to updateFiles (invoked by Files.walkFileTree) in FileReceivingStateMarkerService class. I want to test static call Files.walkFileTree from test class written for FileReceivingStateMarkerService. I need to use PowerMockRunner to test static call as it cannot be tested by simple MockitoJunitRunner.
On running test, I am getting NPE in setUp method at line - mockStatic(Files.class);
Can you please help me to resolve issue on how to configure powermock with Java11 and initialize static class?
I configured powermock in service project (in Java11) as below
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.0-RC.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.0-RC.1</version>
<scope>test</scope>
</dependency>
FileReceivingStateMarkerService class
class FileReceivingStateMarkerService {
private static final Logger LOG = LoggerFactory.getLogger(FileReceivingStateMarkerService.class);
private final FileProcessingActivityRepositoryService fileProcessingActivityRepositoryService;
private final FilePollActivityRepository filePollActivityRepository;
private final FileProcessingRequestRepositoryService fileProcessingRequestRepositoryService;
#Autowired
FileReceivingStateMarkerService(FileProcessingActivityRepositoryService fileProcessingActivityRepositoryService, FilePollActivityRepository filePollActivityRepository,
FileProcessingRequestRepositoryService fileProcessingRequestRepositoryService) {
this.fileProcessingActivityRepositoryService = fileProcessingActivityRepositoryService;
this.filePollActivityRepository = filePollActivityRepository;
this.fileProcessingRequestRepositoryService = fileProcessingRequestRepositoryService;
}
#Scheduled(fixedDelayString="#{${fileprocess.filemonitor.interval.minutes}*60*1000}")
void updateFiles() {
List<FileProcessingRequest> requests = fileProcessingRequestRepositoryService.getFileProcessingRequests();
LOG.debug("Running file receiving state");
requests.forEach(request -> {
LOG.debug("Looking at location {}", request.getFileLocation());
final var fileVisitor = new FileReceivingStateMarkerFileVisitor(filePollActivityRepository
, fileProcessingActivityRepositoryService
, request);
try {
Files.walkFileTree(Path.of(request.getFileLocation()), Collections.emptySet(), 1, fileVisitor);
} catch(Exception e) {
LOG.debug(e.getMessage());
}
});
}
}
Test class for FileReceivingStateMarkerService
package com.experianhealth.rfp.scheduler;
import com.experianhealth.rfp.core.DocumentType;
import com.experianhealth.rfp.core.FileProcessingRequest;
import com.experianhealth.rfp.dao.FilePollActivityRepository;
import com.experianhealth.rfp.service.FileProcessingActivityRepositoryService;
import com.experianhealth.rfp.service.FileProcessingRequestRepositoryService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.mockito.ArgumentMatchers.any;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
#RunWith(PowerMockRunner.class)
#PowerMockIgnore({"com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "org.w3c.*"})
#PrepareForTest(FileReceivingStateMarkerService.class)
public class FileReceivingStateMarkerServicePowerTest {
#Mock
private FileProcessingActivityRepositoryService fileProcessingActivityRepositoryService;
#Mock
private FilePollActivityRepository filePollActivityRepository;
#Mock
private FileProcessingRequestRepositoryService fileProcessingRequestRepositoryService;
#Before
public void setUp() throws Exception {
mockStatic(Files.class);
}
#Test
public void updateFiles() throws Exception {
String rootDir = "C:\\files_processor";
List<FileProcessingRequest> requests = new ArrayList<>();
FileProcessingRequest request = new FileProcessingRequest();
request.setClientId("123");
request.setTradingPartnerId("123");
request.setDocumentId(DocumentType.Payer);
request.setFileLocation(rootDir);
requests.add(request);
final var fileVisitor = new FileReceivingStateMarkerFileVisitor(filePollActivityRepository
, fileProcessingActivityRepositoryService
, request);
try {
PowerMockito.when(Files.walkFileTree(Path.of(request.getFileLocation() ), Collections.emptySet(), 1, fileVisitor))
.thenReturn(any());
} catch(Exception e) {
System.out.println(e.getMessage());
}
}
}
I want to collect metrics for particular REST API
Suppose I have a URL like /company/{companyName}/person/{id}
Is it possible to collect metrics across
/company/test/person/{id}
/compaby/test2/person/{id}
There's no out-of-the-box support for it but you can provide your own WebMvcTagsProvider to implement it via a Spring bean.
Note that it could lead to tag explosion and end up with OOM if there's any possibility to companyName path variable explosion by a mistake or attack.
In case you are using Spring and RestTemplate for http call, you can register MetricsClientHttpRequestInterceptor with your RestTemplate .
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.actuate.metrics.web.client.MetricsRestTemplateCustomizer;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
#Component
#AutoConfigureAfter({MetricsAutoConfiguration.class})
public class RestClientMetricConfiguration {
private final ApplicationContext applicationContext;
#Autowired
public RestClientMetricConfiguration(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
#PostConstruct
public void init() {
MetricsRestTemplateCustomizer restTemplateCustomizer =
applicationContext.getBean(MetricsRestTemplateCustomizer.class);
applicationContext.getBeansOfType(RestTemplate.class).values().forEach(restTemplateCustomizer::customize);
}
}
And use Below method provided by spring RestTemplate to make http call.
public <T> ResponseEntity<T> exchange(String url, HttpMethod method, #Nullable HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
Type type = responseType.getType();
RequestCallback requestCallback = this.httpEntityCallback(requestEntity, type);
ResponseExtractor<ResponseEntity<T>> responseExtractor = this.responseEntityExtractor(type);
return (ResponseEntity)nonNull(this.execute(url, method, requestCallback, responseExtractor, uriVariables));
}
This is the new file I've added in addition to the existing Persistenceconfig.Java. I'm getting this entity manager as 2 found.
we're not using any xml config except for the jpa repositories in spring-data.xml
The issues is occuring only for one package created newly for logging activity and that is also included in jpa repository.
Before adding the below class, everything is normal previously
package com.jumbotree.kumcha.config;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
//import org.springframework.orm.hibernate5.HibernateExceptionTranslator;
import org.springframework.orm.hibernate4.HibernateExceptionTranslator;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#Configuration
#EnableTransactionManagement
//#PropertySource("classpath:kumcha.properties")
#PropertySource("file:/opt/jumbotree/kumcha2/kms.properties")
#EnableJpaRepositories(basePackages = "com.jumbotree.kumcha.crm.model", entityManagerFactoryRef = "createEntityManagerFactoryChargingBean", transactionManagerRef = "createChargingTransactionManagerBean")
#ImportResource("classpath:spring-data.xml")
public class ChargingPersistenceConfig {
#Autowired
private Environment env;
private static final Logger LOGGER = LoggerFactory.getLogger(ChargingPersistenceConfig.class);
#Bean
public DataSource createChargingDataSourceBean() {
LOGGER.info("Charging Datasource created...");
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("charging.db.driver"));
dataSource.setUrl(env.getProperty("charging.db.url"));
dataSource.setUsername(env.getProperty("charging.db.username"));
dataSource.setPassword(env.getProperty("charging.db.password"));
return dataSource;
}
//Here is the entity manager added and causing this issue
#Bean //(name = "entityManagerFactoryCharging")
#PersistenceContext (unitName="chargingPU")
public FactoryBean<EntityManagerFactory> createChargingEntityManagerFactoryBean(#Qualifier("createChargingDataSourceBean") DataSource dsc) {
LocalContainerEntityManagerFactoryBean chargingentityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
LOGGER.info("Charging entityman created...");
try {
chargingentityManagerFactoryBean.setDataSource(createChargingDataSourceBean());
chargingentityManagerFactoryBean.setPackagesToScan("com.jumbotree.kumcha.crm.model");
chargingentityManagerFactoryBean.setJpaVendorAdapter(createJpaVendorAdapterBean());
chargingentityManagerFactoryBean.setJpaProperties(createJpaProperties());
} catch (Exception e) {
// TODO: handle exception
LOGGER.error(e.toString());
}
return chargingentityManagerFactoryBean;
}
private Properties createJpaProperties() {
LOGGER.info("hibernate.show_sql :::: "+env.getProperty("hibernate.show_sql"));
return new Properties() {
{
// setProperty("hibernate.hbm2ddl.auto", "create-drop");
setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
setProperty("hibernate.format_sql", env.getProperty("hibernate.format_sql"));
// setProperty("hibernate.cache.use_second_level_cache", "true");
// setProperty("hibernate.cache.provider_class", "org.hibernate.cache.EhCacheProvider");
// setProperty("shared-cache-mode", "DISABLE_SELECTIVE");
//<property name="hibernate.cache.use_second_level_cache" value="true"/>
//setProperty("hibernate.connection.zeroDateTimeBehavior", "convertToNull");
}
};
}
private JpaVendorAdapter createJpaVendorAdapterBean() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
// jpaVendorAdapter.setDatabase(Database.valueOf(env.getProperty("db.name")));
jpaVendorAdapter.setShowSql(true);
// jpaVendorAdapter.setGenerateDdl(true);
jpaVendorAdapter.setDatabasePlatform(env.getProperty("hibernate.dialect"));
return jpaVendorAdapter;
}
#Bean //(name = "transactionManager")
public PlatformTransactionManager createChargingTransactionManagerBean() throws Exception {
LOGGER.info("Charging transactionMan created...");
JpaTransactionManager chargingtransactionManager = new JpaTransactionManager();
chargingtransactionManager.setEntityManagerFactory(createChargingEntityManagerFactoryBean(createChargingDataSourceBean()).getObject());
return chargingtransactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor createPersistenceExceptionTranslationPostProcessor() {
return new PersistenceExceptionTranslationPostProcessor();
}
// Required if using Hibernate 4
#Bean
public PersistenceExceptionTranslator createPersistenceExceptionTranslatorBeaan() {
return new HibernateExceptionTranslator();
}
}
LoggerRepository cannot choose one of the 2 beans createChargingEntityManagerFactoryBean and createEntityManagerFactoryBean
Make one of them primary and/or specify qualifier. (BTW sometimes even with qualifier it's necessary to make one of beans primary)
Cannot suggest cconfig changes without your code.
In my entities I have some hibernate annotations for validation, like #NotEmpty, #Pattern.. and others
In my controller, on save action, it has an #Valid parameter.
But if any entity has any required field, and there is no annotation I will have problems.
So I would like to test each entity, to ensure they have the necessary notes.
Something like:
#Test(expect=IllegalArgumentException.class)
public void testAllNull() {
Person p = new Persson(); // Person name has an #NotEmpty
validator.validate(p);
}
But how to validate it? Who is called to check #Valid?
Thanks.
I found out how to check:
#Autowired
private LocalValidatorFactoryBean validator;
...
validator.validateProperty(object, propertyName)
Here is a Spring v4.1.x based example of a test validating presence and processing of the #Valid annotation and building of custom JSON response in case of an error.
jUnit
import com.fasterxml.jackson.core.type.TypeReference;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import javax.inject.Inject;
import java.util.List;
import static org.abtechbit.miscboard.util.JsonUtils.toJson;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {
RegistrationValidationTest.MockDependencies.class,
})
public class RegistrationValidationTest {
#Inject
MockMvc mvc;
#Test
public void validatesRegistration() throws Exception {
Registration registration = ... //build an invalid Registration object
MvcResult result = mvc.perform(post(RegistrationController.CONTEXT_REGISTER).
contentType(MediaType.APPLICATION_JSON).
content(toJson(registration))).
andExpect(status().isBadRequest()).
andExpect(content().contentType(MediaType.APPLICATION_JSON)).
andReturn();
assertThat(result.getResolvedException(), is(notNullValue()));
String content = result.getResponse().getContentAsString();
assertThat(content, is(notNullValue()));
List<Message> messages = JsonUtils.fromJson(content, new TypeReference<List<Message>>() {
});
assertThat(messages.size(), is(1));
}
public static class MockDependencies {
#Bean
public MockMvc mvc() {
return MockMvcBuilders.standaloneSetup(new RegistrationController()).build();
}
}
}
Controller
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
import java.util.stream.Collectors;
#Controller
public class RegistrationController
{
public static final String CONTEXT_REGISTER = "/register";
#RequestMapping(value = CONTEXT_REGISTER, method = RequestMethod.POST)
#ResponseBody
public String register(#RequestBody #Valid Registration registration) {
//perform registration
}
#ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<List> handleValidationException(MethodArgumentNotValidException ex) {
//Build a list of custom Message{String message;} objects
List<Message> messages = ex.getBindingResult().getAllErrors().
stream().map(e->new Message(e.getDefaultMessage())).collect(Collectors.toList());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).contentType(MediaType.APPLICATION_JSON).body(messages);
}
}
Spring MVC Test Framework might be a good choice. By using this, you can be assured that validations in your tests runs codes as Spring #MVC actually works.
Actually, the #Valid annotation is detected by HandlerMethodInvoker, which processes annotations on the handler methods of Spring controllers. Internally, the actual validation logic is delegated to the Validator bean depending on your application context settings. (Hibernate Validator is widely used.)
By default configuration (e.g. <mvc:annotation-driven />), LocalValidatorFactoryBean is used internally to process #Valid annotation as #Falci noted, but it may differ time to time. Instead, Spring MVC Test Framework provides the same environment as the main application uses, hence a good choice.