Inject Spring bean within RESTEasy Resource at Test time - rest

Within a Unit/Integration Test, I'm trying to use the RESTEasy embedded server TJWSEmbeddedJaxrsServer or POJOResourceFactory inorder to simulate through a MockHttpRequest.get("/data") a resource call for test purpose.
My problem is that based on the use of the server or the Resource factory I'm not able to have a non null instance of spring beans which are injected normally within my resources.
Here's some code for clarification, thanks in advance.
Spring application context :
<context:annotation-config />
<context:component-scan base-package="com.cdcfast.service" />
<bean id="simpleResource" class="com.cdcfast.rest.SimpleResource" />
SimpleResource.java :
#Component
#Path("/data")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class SimpleResource {
#Autowired
private SimpleService service;
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<Data> getData() {
return MockDataBase.getInstance().getRows();
}
Unit Test :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath*:/test/spring/testApplicationContext.xml" })
public class FakeTest {
private Dispatcher dispatcher;
#Before
public void before() {
dispatcher = MockDispatcherFactory.createDispatcher();
POJOResourceFactory noDefaults = new POJOResourceFactory(SimpleResource.class);
dispatcher.getRegistry().addResourceFactory(noDefaults);
}
#Test
public void aTestThatAlwaysPass() throws URISyntaxException {
MockHttpRequest request = MockHttpRequest.get("/data");
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
Assertions.assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
Assertions.assertThat(response.getContentAsString()).isNotNull().isNotEmpty();
}
}

I've had this before because the RESTEasy factories create the POJO rather than Spring so they don't get wired up which can be worked around in the full container but is less easy in a test. The best way around this is to get a handle to your POJO once the factory creates it and then do something similar to this:
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(myPojo);
I personally ended up having Spring create the RESTEasy beans using the RESTEasy-Spring plugin and then launching my tests using Jetty, not sure if that is an option for you though.

I exeprienced same problem and i'have solved in similar way as James did:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:spring-context-test.xml" })
public class TestMyService {
Dispatcher dispatcher;
private String username = "user";
#Autowired
ApplicationContext context;
#Before
public void setUp() {
MyService g = new MyService(); //rest service with #autowired spring beans
context.getAutowireCapableBeanFactory().autowireBean(g);
dispatcher = MockDispatcherFactory.createDispatcher();
dispatcher.getRegistry().addSingletonResource(g);
}
#Test
public void TestRest() {
MockHttpRequest request;
try {
request = MockHttpRequest.get("/rest/service").header("LOGON_USER", username);
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertTrue("Error, unexpected status code: " + response.getStatus(), response.getStatus() == 200);
LoggerFactory.getLogger(this.getClass()).info("********** " + response.getContentAsString());
} catch (URISyntaxException e) {
Log.error(e.getMessage(), e);
fail(e.getMessage());
}
}
}

Related

Integration Tests for RESTEasy Endpoint

I want to perform integration tests on my REST endpoint but am running into issues.
Below is my endpoint. NOTE: I cannot change this part of the code.
#Path("/people")
public class PersonResource {
private final PersonService personService;
#Inject
public PersonResource(final PersonService personService) {
this.personService = personService;
}
#GET
#Produces("application/json")
public List<Person> getPersonList() {
return personService.getPersonList();
}
}
From what I've been able to find online, I have the following basic structure for my test.
public class PersonResourceTest {
private Dispatcher dispatcher;
private POJOResourceFactory factory;
#Before
public void setup() {
dispatcher = MockDispatcherFactory.createDispatcher();
factory = new POJOResourceFactory(PersonResource.class);
dispatcher.getRegistry().addResourceFactory(factory);
}
#Test
public void testEndpoint() throws URISyntaxException {
MockHttpRequest request = MockHttpRequest.get("people");
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
System.out.print("\n\n\n\n\n" + response.getStatus() + "\n\n\n\n\n");
System.out.print("\n\n\n\n\n" + response.getContentAsString() + "\n\n\n\n\n");
}
}
However, this results in the following error on the last line of the setup method.
java.lang.RuntimeException: RESTEASY003190: Could not find constructor for class: my.path.PersonResource
I explored the Registry API and thought maybe I should have been using addSingletonResource instead, so I changed the last line of setup to dispatcher.getRegistry().addSingletonResource(personResource); and added the following.
#Inject
private PersonResource personResource;
But that results in a NullPointerException on the last line of setup.
The sparse documentation on the mocking isn't very helpful. Can anyone point out where I'm going wrong? Thanks.
You need to do two things
Add a no arguments constructor to your source class:
public PersonResource() {
this(null)
}
In the test class, initialize the PersonResource class with an instance of PersonService class:
dispatcher.getRegistry().addSingletonResource(new PersonResource(new PersonService()));
If needed, the PersonService class can be mocked:
private Dispatcher dispatcher;
#Mock
private PersonService service;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
dispatcher = MockDispatcherFactory.createDispatcher();
PersonResource resource= new PersonResource(service);
ispatcher.getRegistry().addSingletonResource(resource);
}
Hope it helps!

Unit Testing Rest Services with Spring Boot and JUnit

I have a basic SpringBoot app. using Spring Initializer, JPA, embedded Tomcat, Thymeleaf template engine, and package as an executable JAR file. I've defined this Rest method to get a User
#GetMapping(path = "/api/users/{id}",
consumes = "application/json",
produces = "application/json")
public ResponseEntity<User> getUser
(HttpServletRequest request,
#PathVariable long id) {
User user = checkAccess(request, id);
return ResponseEntity.ok(user);
}
I've created this Junit to test it
#ContextConfiguration(classes={TestSystemConfig.class})
#RunWith(SpringRunner.class)
#WebMvcTest(UserResourceController.class)
public class UserResourceControllerTests {
#Autowired
private MockMvc mvc;
#MockBean
private UserResourceController UserResourceController;
#Test
public void getUser() throws Exception {
mvc.perform(get("/api/users/1")
.with(user("pere.peris#gmail.com").password("password"))
.contentType(APPLICATION_JSON))
.andExpect(status().isOk());
}
}
But I got this error when I run the test:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalArgumentException: Name for argument type [long] not available, and parameter name information not found in class file either.
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:71)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:166)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)
The reason is because you are mocking your controller. This is not necessary when you have #WebMvcTest(UserResourceController.class)
This should work.
#ContextConfiguration(classes={TestSystemConfig.class})
#RunWith(SpringRunner.class)
#WebMvcTest(UserResourceController.class)
public class UserResourceControllerTests {
#Autowired
private MockMvc mvc;
#Test
public void getUser() throws Exception {
mvc.perform(get("/api/users/1")
.with(user("pere.peris#gmail.com").password("password"))
.contentType(APPLICATION_JSON))
.andExpect(status().isOk());
}
}

Spring restful service test case fail HTTP status is 500

I want to implement test case for spring restful web services which return a json
MY controller test class is :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {WebAppContext.class,JpaTestConfiguration.class
})
#WebAppConfiguration
public class DominProfileRestControllerTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
private MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(),
Charset.forName("utf8"));
#Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
public void testGetDomainProfile() throws Exception {
String profileId = domainProfile.getId().toString();
System.out.print("testing restful"+profileId);
mockMvc.perform(get("/service/domainprofile/get/{id}", profileId) )
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$.city", is("Chandigrah")));
/* mockMvc.perform(get("/service/domainprofile/get/{id}",profileId).accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andExpect(content().contentType("text/plain;charset=ISO-8859-1"))
.andExpect(content().string("hello Prashant"));
*/
}
My Controller class Is :
#RestController
#RequestMapping("/service/domainprofile")
public class DominProfileRestController {
#Autowired
private JpaDomainProfileRepository jpaDomainProfileRepository;
#RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
public DomainProfileResource getDomainProfile(#PathVariable String id) {
JpaDomainProfile domainProfile = jpaDomainProfileRepository.findOne(Long.valueOf(id));
DomainProfileResource domainProfileResource = new DomainProfileResource();
System.out.println("domainProfile.getCity()*************" + domainProfile.getCity());
System.out.println("domainProfile.getAddress()*************" + domainProfile.getAddress());
domainProfileResource.setCity(domainProfile.getCity());
domainProfileResource.setAddress(domainProfile.getAddress());
// return new ResponseEntity<DomainProfileResource>(domainProfileResource, HttpStatus.OK);
return domainProfileResource;
// return domainProfile;
}
}
When I run test case I got An error while we got values in domainprofile.city and domainprofile.address.
Error Is :
java.lang.AssertionError: Status
Expected :200
Actual :500
It Is Working Fine When I return a plain text
can you do this
mockMvc.perform(get("/service/domainprofile/get/{id}", profileId) )
.andDo(print());
this will print the full response with exception , now if you see HttpMessageNotWritableException which was the issue I was facing , you should try to serialize your object using jackson and see if it works (spring internally uses Jackson ). For example , If any of your fields are null the Serialization will fail.

Camel CXF POJO mode using Java DSL

I have a pre-existing web service "connect" (SOAP) I would like to call without using the Swing framework if possible. I have followed the contact first development generating my java files using cxf/wsdl2java tool.
I wish for the userName and password to be extracted from the java object and placed in a SOAP object then sent onot my localhost web service.
When sending the Connect object as a body to the "direct:start" I get an exception...
Caused by: java.lang.IllegalArgumentException: Get the wrong parameter size to invoke the out service, Expect size 2, Parameter size 1. Please check if the message body matches the CXFEndpoint POJO Dataformat request.
I've checked the first argument is actually an instance of the Connect object passed in.
Do I need some additional annotations in the one of the classes, is the method of testing invalid or
is there an alternative pattern I should follow?
public class TestConnectCXF extends CamelTestSupport
{
#Override
protected RouteBuilder createRouteBuilder() throws Exception
{
return new RouteBuilder()
{
String cxfAddressLine = "cxf:http://localhost:8081/nuxeo/webservices/privateadservice?wsdlURL=wsdl/privateadservice.wsdl" //
+ "&dataFormat=POJO" //
+ "&serviceClass=com.sandbox.camelfeed.PrivateAdServiceInterface" //
+ "&serviceName={http://ws.sandboxtest.com/}PrivateAdService" //
+ "&synchronous=true" //
+ "&loggingFeatureEnabled=true" //
+ "&portName={http://ws.sandboxtest.com/}PrivateAdServiceInterfacePort";
#Override
public void configure() throws Exception
{
from("direct:start").to(cxfAddressLine).to("mock:end");
}
};
}
#Test
public void testConnectViaPojo() throws InterruptedException
{
Connect connectToServer = new Connect();
connectToServer.setUserName("FakeUser");
connectToServer.setPassword("scrubbed");
template.sendBody("direct:start", connectToServer);
Thread.sleep(1000);
}
}
I'm new to camel and web services so any helpful pointers would be greatly appreciated.
Additional info
Using camel 2.10, Java 1.6
Classes generated from wsdl2java
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "connect", propOrder = {
"userName",
"password"
})
public class Connect {
protected String userName;
protected String password;
public String getUserName() {
return userName;
}
public void setUserName(String value) {
this.userName = value;
}
public String getPassword() {
return password;
}
public void setPassword(String value) {
this.password = value;
}
}
#WebService(targetNamespace = "http://ws.sandboxtest.com/", name = "PrivateAdServiceInterface")
#XmlSeeAlso({ObjectFactory.class})
public interface PrivateAdServiceInterface {
// Omitted Code relating to other web calls
#WebResult(name = "return", targetNamespace = "")
#RequestWrapper(localName = "connect", targetNamespace = "http://ws.sandboxtest.com/", className = "com.sandbox.camelfeed.Connect")
#WebMethod
#ResponseWrapper(localName = "connectResponse", targetNamespace = "http://ws.sandboxtest.com/", className = "com.sandbox.camelfeed.ConnectResponse")
public java.lang.String connect(
#WebParam(name = "userName", targetNamespace = "")
java.lang.String userName,
#WebParam(name = "password", targetNamespace = "")
java.lang.String password
) throws ClientException_Exception;
}
#XmlRegistry
public class ObjectFactory {
{
// Omitted other web calls information
private final static QName _Connect_QNAME = new QName("http://ws.sandboxtest.com/", "connect");
#XmlElementDecl(namespace = "http://ws.sandboxtest.com/", name = "connect")
public JAXBElement<Connect> createConnect(Connect value) {
return new JAXBElement<Connect>(_Connect_QNAME, Connect.class, null, value);
}
}
In my experience there are some things in Camel, like calling a SOAP Web service or making a REST call, that are easier to do in a custom processor, than using a component like CXF, HTTP or HTTP4.
I usually work with Spring, so I tend to use either Spring REST template or the JaxWsPortProxyFactoryBean (for Webservice calls) for outbound calls.
Here is an example using a JAX-WS call:
public class WebServiceProcessorBean {
#Autowired
private JAXWSProxy theProxy;
public void callWebservice(Exchange exchange) {
Response response = theProxy.call();
//Do something with the response and Exchange.
}
}
The definition in the Spring application context:
<bean id="theProxyService" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<property name="serviceInterface" value="XXX"/>
<property name="wsdlDocumentUrl" value="http://xxxxx.wsdl"/>
<property name="namespaceUri" value="xxxx"/>
<property name="serviceName" value="xxxx"/>
<property name="portName" value="xxxxx"/>
</bean>
Use the WebServiceProcessorBean defined in Spring application context with beanRef() DSL method.
.beanRef("theProxyService", "callWebservice")
I try also dig into Apache Camel with CXF:).
I think exception, which is throws, is about problem with number of argument.
template.sendBody(what_is_called, input_parameter_s, output_parameter);
Output parameter is the most probably return value from calling of cxf webservices.

Spring Data MongoTemplate not throwing DataAccessException

I am trying to learn MongoDB and in the same time write a simple REST application using Spring framework.
I have a simple model:
#Document
public class Permission extends documentBase{
#Indexed(unique = true)
private String name;
public Permission(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Then I have a simple DAO:
#Repository
#Transactional
#Profile({"production","repositoryTest","mongoIntegrationTest"})
public class DaoImpl implements DAO {
#Autowired
protected MongoTemplate mongoTemplate;
public <T> T addObject(T object) {
mongoTemplate.insert(object);
return object;
}
The I have my integration tests:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:mvc-dispatcher-servlet.xml", classpath:IntegrationContext.xml"},loader = TestXmlContextLoader.class)
#ActiveProfiles("mongoIntegrationTest")
public class RepositoryIntegrationTest extends AccountTestBase{
#Autowired DAO repository;
#Autowired WebApplicationContext wac;
#Test
public void AddPermission() {
Permission permission_1 = new Permission("test");
Permission permission_2 = new Permission("test");
repository.addObject(permission_1);
repository.addObject(permission_2);
}
}
My configuration:
<!-- MongoDB host -->
<mongo:mongo host="${mongo.host.name}" port="${mongo.host.port}"/>
<!-- Template for performing MongoDB operations -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"
c:mongo-ref="mongo" c:databaseName="${mongo.db.name}"/>
I am expecting that, on adding "permission_2" their would be a exception thrown from MongoDB, which would be translated by Spring,, and catched as a DataAccessException in the DAO.
Looking at the log files from MongoDb I can see that a duplicated exception is thrown but it never reaches my DAO.
So,, I guess I am doing something wrong,,, but at the moment,, I am blind to my own misstakes.
//lg
Make sure you configure the WriteConcern of the MongoTemplate to something non-default (e.g. WriteConcern.SAFE). By default MongoDB is in fire-and-forget mode and does not throw exceptions on index violations or server errors in general.
Still struggling with this.
Finnally I succeded to get the exeption translation working. MongoDb throws a exception which is translated to Spring Data exception.
Now I am stuck with another problem.
My DAO shown above has also the following code:
#ExceptionHandler(DataAccessException.class)
public void handleDataAccessException(DataAccessException ex) {
// For debug only
DataAccessException test = ex;
test.printStackTrace();
}
I was expecting this code to catch the exception thrown,, but this is not the case.
Why not?
//lasse