I started to use the new MVC Testframework of Spring 3.2 and got stuck with getting 406 HTTP Response Codes for all my test cases.
The testcase is plain simple
public class LocationResouceTest {
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
#Test
public void testGetLocationByPlzPattern() throws Exception {
// here I need to define the media type as a static var from MediaType
this.mockMvc.perform(get("/someurl?someparam=somevalue")).andExpect(status().isOk());
}
}
the corresponding resource is
#Controller
// here I need to define the media type as string
#RequestMapping(value = "/someurl", produces = "application/json; charset=UTF-8")
public class LocationResource {
#ResponseBody
#RequestMapping(method = RequestMethod.GET)
public ArrayList<DTO> getAllIndex(#RequestParam("someparam") String param) {
return ... //the list of DTO classes is transformed to json just fine if called with curl
}
}
I am sure it is because of a wrong media type but I cannot figure out why.
The trace of the failing testcase:
java.lang.AssertionError: Status expected:<200> but was:<406> at
org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:60)
at
org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:89)
at
org.springframework.test.web.servlet.result.StatusResultMatchers$5.match(StatusResultMatchers.java:546)
at
org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:141)
at
de.yourdelivery.rest.location.LocationResouceTest.testGetLocationByPlzPattern(LocationResouceTest.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597) at
org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at
org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at
org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at
org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at
org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at
org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at
org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at
org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at
org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at
org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at
org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at
org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at
org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at
org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at
org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at
org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at
org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
If you have a #Configuration class, you can add the
#EnableWebMvc
annotation instead of using an XML configuration with <mvc:annotation-driven />.
It is necessary to have both #EnableWebMvc
and .accept(MediaType.APPLICATION_JSON)
This might be caused by not having any MVC configuration in the Spring test context. When using something like:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration("/test-context.xml")
...then that test-context.xml file should also include things like:
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager">
<mvc:message-converters>
<bean id="..." class=
"org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
<bean id="..."
class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean id="..."
class="org.springframework.http.converter.FormHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="contentNegotiationManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="defaultContentType" value="application/json" />
<property name="mediaTypes">
<value>
json=application/json
xml=application/xml
</value>
</property>
</bean>
One can easily test if the above is the problem, with a controller that does not specify anything special (such as: no produces in #RequestMapping), and hence does not need any content negotiation:
#RequestMapping(value = "/foo", method = RequestMethod.GET)
#ResponseBody
public String getFoo() {
return "bar";
}
...with:
#Test
public void getFoo() throws Exception {
MvcResult result =
this.mockMvc.perform(get("/foo").accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andReturn();
Assert.assertEquals(result.getResponse().getContentAsString(), "bar");
}
You need to add the following code to spring xml to serialize POJO in jackson.
<annotation-driven />
You are missing the <mvc:annotation-driven /> in the configuration xml file.
The spring way of doing things is, i think, to use a HttpResponseEntity, or return a modelandview.
For example :
#ResponseBody
ResponseEntity<String> getFoo() {
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setContentType(MediaType.APPLICATION_JSON);
String test = "{\"foo\":{\"title\": \"Stack\"}}";
return new ResponseEntity<String>(test, responseHeaders, HttpStatus.OK);
}
(I'd be interested in any further progress you make as its all pretty new)
I think the fix is to modify the request this way:
this.mockMvc.perform(get("/someurl?someparam=somevalue").contentType(MediaType.APPLICATION_JSON)).andExpect..
I met same problem just now, and is resolved by changing the return type of the Controller to String.
And return a JSON string instead of an object directly. It does works.
Gson gson = new Gson();
return gson.toJson(dto);
Related
I'm novice to all this stuff, writing test for Spring MVC controller and got error above, tried solution provided in
Spring 3.2.5 error "java.lang.AssertionError: No ModelAndView found" for all my controller Unit Test - still no luck! Could pls anyone help? Thanks in advance!
let me know if anything else needed on top of code below.
test class:
(note, that printout of getBeanDefinitionNames() among others returns "homeController" - so I assume controller is found and initialized )
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes={WebDispatcherConfig.class,DataConfig.class})
#WebAppConfiguration
public class HomeControllerTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext wac ;
#Before
public void setUp() {
this.mockMvc = webAppContextSetup(wac).build();
System.out.println(Arrays.toString(wac.getBeanDefinitionNames()));
}
#Test
public void testHome() throws Exception {
mockMvc
.perform(get(WebDispatcherConfig.WEBAPP_PREFIX))
.andExpect(view().name(HomeController.HOME))
.andExpect(model().attributeExists(WebDispatcherConfig.PREFIX_NAME));
}
}
web context config class:
#EnableWebMvc
#ComponentScan("io.github.d2edev.mywebapp.web")
public class WebDispatcherConfig extends WebMvcConfigurerAdapter {
public static final String WEBAPP_PREFIX="/web";
public static final String PREFIX_NAME="wepbrefix";
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
}
controller (note it's already in package reflected in #ComponentScan in config class above):
package io.github.d2edev.mywebapp.web;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import io.github.d2edev.mywebapp.config.WebDispatcherConfig;
#Controller
#RequestMapping("/")
public class HomeController {
public static final String HOME="home";
#RequestMapping(method=RequestMethod.GET)
public String home(Model model){
model.addAttribute(WebDispatcherConfig.PREFIX_NAME, WebDispatcherConfig.WEBAPP_PREFIX);
return HOME;
}
}
stacktrace:
java.lang.AssertionError: No ModelAndView found
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:39)
at org.springframework.test.util.AssertionErrors.assertTrue(AssertionErrors.java:72)
at org.springframework.test.web.servlet.result.ViewResultMatchers$2.match(ViewResultMatchers.java:68)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:171)
at test.web.HomeControllerTest.testHome(HomeControllerTest.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:254)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:193)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Solved!
Reason is that in my real app servlet is mapped to "/web" and HomeController to "/" which results that controller serves requests to "/web".
So I provided same "/web" address for GET request in controller test class, but when we create MockMvc, as I understood, we can't make mapping like we do in app init class, so "test" controller was waiting for my request at "/".
To make it work, I should either explicitly put
.perform(get("/"))
or make on-fly remapping with additional code like proposed here:
MockMvc WebAppConfiguration: Load servlet mappings in web.xml
Thanks!
So I have this test case:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:rest-context-test.xml")
public class CustomerControllerTest {
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders
.standaloneSetup(new CustomerController()).build();
}
#Test
public void testGetCustomerById() throws Exception {
mockMvc.perform(get("/customers/{ccid}", 1)).andExpect(status().isOk())
.andExpect(content().contentType("application/json"))
.andExpect(jsonPath("$.ccid").value("1"));
}
}
That loads rest-context-test.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">
<bean id="customerServiceImpl"
class="myorg.service.impl.MockCustomerServiceImpl" />
</beans>
With the hope of being able to AutoWire customerServiceImpl into my controller:
#Controller
#RequestMapping("customers")
public class CustomerController {
private static Logger Logger = LoggerFactory
.getLogger(CustomerController.class);
#Autowired
#Qualifier("customerServiceImpl")
private CustomerService customerService;
#RequestMapping(value = "/{ccid}", method = RequestMethod.GET, produces = "application/json")
#ResponseStatus(HttpStatus.OK)
#ResponseBody
public Customer getCustomerById(#PathVariable Integer ccid)
throws BadRequestException, ServerErrorException,
ResourceNotFoundException {
Customer c = null;
try {
c = customerService.getCustomer(ccid);
} catch (IllegalArgumentException iae) {
// HTTP 400
Logger.error("Invalid arguments submitted", iae);
throw new BadRequestException();
} catch (CsspException ce) {
// HTTP 500
Logger.error("Server error", ce);
throw new ServerErrorException();
}
if (c == null) {
// HTTP 404
throw new ResourceNotFoundException();
}
return c;
}
}
But my unit test is throwing the following trace:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:965)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:844)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:829)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:66)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:168)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:136)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:141)
at myorg.rest.controller.CustomerControllerTest.testGetCustomerById(CustomerControllerTest.java:41)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.NullPointerException
at myorg.rest.controller.CustomerController.getCustomerById(CustomerController.java:134)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle (ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod (RequestMappingHandlerAdapter.java:745)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal (RequestMappingHandlerAdapter.java:686)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:953)
... 38 more
This null pointer is thrown when the Controller tries to access customerService:
#Autowired
#Qualifier("customerServiceImpl")
private CustomerService customerService;
Why isn't my MockCustomerServiceImpl being AutoWired into the Controller?
Note: package names have been changed to protect the innocent
From Spring documentation:
The "webAppContextSetup" loads the actual Spring MVC configuration resulting in a more complete integration test. Since the TestContext framework caches the loaded Spring configuration, it helps to keep tests running fast even as more tests get added. Furthermore, you can inject mock services into controllers through Spring configuration, in order to remain focused on testing the web layer.
The "standaloneSetup" on the other hand is a little closer to a unit test. It tests one controller at a time, the controller can be injected with mock dependencies manually, and it doesn’t involve loading Spring configuration. Such tests are more focused in style and make it easier to see which controller is being tested, whether any specific Spring MVC configuration is required to work, and so on. The "standaloneSetup" is also a very convenient way to write ad-hoc tests to verify some behavior or to debug an issue.
From this I understand that, if I need an .xml as a Spring configuration file to be loaded, then I need to go with the "webAppContextSetup". If I just need very simple tests with my Controller, without the need of a Spring configuration, then I go with the "standaloneSetup" approach. In your case, I think you need the "webAppContextSetup".
You forgot to create your mock objects and then inject them into your controller like so
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:rest-context-test.xml")
public class CustomerControllerTest
{
#Mock
private CustomerService customerService;
#InjectMocks
private CustomerController customerController;
private MockMvc mockMvc;
#Before
public void setup()
{
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders
.standaloneSetup(customerController).build();
}
#Test
public void testGetCustomerById() throws Exception
{
mockMvc.perform(get("/customers/{ccid}", 1)).andExpect(status().isOk())
.andExpect(content().contentType("application/json"))
.andExpect(jsonPath("$.ccid").value("1"));
}
}
It helped me to fix the NullPointerException by adding annotations #RunWith(SpringRunner.class) ,#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) and #AutoConfigureMockMvc
Here is code that worked for me-
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureMockMvc
public class MyTestClass {
#Autowired
private MockMvc mockMvc;
#Test
public void myClassController() throws Exception {
Object obj = new Object();
obj.setA(1);
obj.setB(2);
obj.setC(3);
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(obj); // this is the json body
mockMvc.perform(post("/ENDPOINT")
.contentType(MediaType.APPLICATION_JSON)
.content(jsonString))
.andDo(print())
.andExpect(status().isOk());
}
I have controller:
#RestController
public class CheckPermissionContr {
#PreAuthorize("hasRole('ROLE_USER')")
#RequestMapping(value = "/permission", method = RequestMethod.GET)
public String checkPermission(#RequestParam("id") UUID id) {
When I call it from unit test like:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration("file:src/main/webapp/WEB-INF/mvc-dispatcher-servlet.xml")
public class CheckPermissionContrTest {
#SuppressWarnings("SpringJavaAutowiringInspection")
#Autowired
protected WebApplicationContext wac;
private MockMvc mockMvc;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
BasicConfigurator.configure();
this.mockMvc = webAppContextSetup(wac).build();
final GeneralAuthentication authen = mock(GeneralAuthentication.class);
user = mock(User.class);
when(user.getId()).thenReturn(UUID.randomUUID());
final GrantedAuthority mockAuth = mock(GrantedAuthority.class);
doReturn("ROLE_USER").when(mockAuth).getAuthority();
Collection<GrantedAuthority> authority = Collections.singleton(mockAuth);
doReturn(authority).when(authen).getAuthorities();
when(authen.getPrincipal()).thenReturn(user);
final SecurityContext secContext = mock(SecurityContext.class);
when(secContext.getAuthentication()).thenReturn(authen);
SecurityContextHolder.setContext(secContext);
}
#Test
public void testCheckPermission() throws Exception {
mockMvc.perform(get("/permission.json").param("id", id.toString())).andExpect(status().isOk()).andDo(print());
When I run test:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for com.XXXXX.GeneralAuthentication$$EnhancerByMockitoWithCGLIB$$6db1e4cf
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:734)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:62)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:170)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:137)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:141)
at com.XXXXX.CheckPermissionContrTest.testCheckPermission(CheckPermissionContrTest.java:121)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:232)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:175)
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for com.XXXXX.GeneralAuthentication$$EnhancerByMockitoWithCGLIB$$6db1e4cf
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199)
at org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParser$AuthenticationManagerDelegator.authenticate(GlobalMethodSecurityBeanDefinitionParser.java:433)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.authenticateIfRequired(AbstractSecurityInterceptor.java:316)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:202)
at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:60)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)
at com.XXXXX.CheckPermissionContr$$EnhancerBySpringCGLIB$$f974fa1c.checkPermission(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHand
But when I replace #PreAuthorize with #Secured("ROLE_USER") everything go smoothly.
Contained by .xml:
WEB-INF/mvc-dispatcher-servlet.xml
<import resource="spring-security.xml"/>
Inside spring-security.xml
<security:global-method-security pre-post-annotations="enabled"/>
<security:http use-expressions="true" auto-config="false" entry-point-ref="restEntryPoint">
<security:intercept-url pattern="/*"/>
</security:http>
<bean id="auhProvider" class="com.XXXXX.AuhProvider">
<constructor-arg name="userRepo" ref="userRepo"/>
</bean>
<security:authentication-manager alias="manager">
<security:authentication-provider ref="auhProvider">
</security:authentication-provider>
</security:authentication-manager>
Additional code:
#Override
public boolean supports(Class<?> aClass) {
return aClass.isAssignableFrom(GeneralAuthentication.class);
}
The com.XXXXX.AuhProvider supports only objects of the type GeneralAuthentication.class. Since you mock authen it no longer has this class, but rather com.XXXXX.GeneralAuthentication$$EnhancerByMockitoWithCGLIB$$6db1e4cf.
The test in the support method must be the other way around:
GeneralAuthentication.class.isAssignableFrom(aClass)
Which means "is aClass GeneralAuthentication.class or a subtype of it".
I'm using Jersey in my REST-application. I need to test it with junit. But I got an com.sun.jersey.api.client.ClientHandlerException. Stacktrace:
SEVERE: The registered message body readers compatible with the MIME media type are:
application/octet-stream ->
com.sun.jersey.core.impl.provider.entity.ByteArrayProvider
com.sun.jersey.core.impl.provider.entity.FileProvider
com.sun.jersey.core.impl.provider.entity.InputStreamProvider
com.sun.jersey.core.impl.provider.entity.DataSourceProvider
com.sun.jersey.core.impl.provider.entity.RenderedImageProvider
*/* ->
com.sun.jersey.core.impl.provider.entity.FormProvider
com.sun.jersey.core.impl.provider.entity.StringProvider
com.sun.jersey.core.impl.provider.entity.ByteArrayProvider
com.sun.jersey.core.impl.provider.entity.FileProvider
com.sun.jersey.core.impl.provider.entity.InputStreamProvider
com.sun.jersey.core.impl.provider.entity.DataSourceProvider
com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider$General
com.sun.jersey.core.impl.provider.entity.ReaderProvider
com.sun.jersey.core.impl.provider.entity.DocumentProvider
com.sun.jersey.core.impl.provider.entity.SourceProvider$StreamSourceReader
com.sun.jersey.core.impl.provider.entity.SourceProvider$SAXSourceReader
com.sun.jersey.core.impl.provider.entity.SourceProvider$DOMSourceReader
com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$General
com.sun.jersey.core.impl.provider.entity.XMLListElementProvider$General
com.sun.jersey.core.impl.provider.entity.XMLRootObjectProvider$General
com.sun.jersey.core.impl.provider.entity.EntityHolderReader
com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class com.example.Student, and Java type class com.example.Student, and MIME media type application/octet-stream was not found
at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:561)
at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:517)
at com.example.servlet.StudentResourceTest.test(StudentResourseTest.java:85)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
I do not know how to fix this bug. I'm looking forward to your help.
My code:
#Path("/student")
#Component
public class StudentResourse {
#Autowired
private StrudentService service;
#Path("/getStudent/{id}")
#GET
#Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Student getStudent(#PathParam("id") long id) {
return service.get(id);
}
}
This class works fine. When I type in browser: http://127.0.0.1:8080/Application/student/getStudent/100500 it shows me student in xml
My test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:configuration.xml")
#TestExecutionListeners({ DbUnitTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class })
public class StudentResourseTest extends JerseyTest {
#Override
protected AppDescriptor configure() {
return new WebAppDescriptor.Builder("com.example.servlet")
.contextPath("context").build();
}
#Override
protected TestContainerFactory getTestContainerFactory() {
return new HTTPContainerFactory();
}
#Test
#DatabaseSetup("dataset.xml")
public void test() throws UnsupportedEncodingException {
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
WebResource service = client.resource(getBaseURI());
ClientResponse response = service.path("getStudent").path("100500")
.accept(MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON)
.get(ClientResponse.class);
Student student = (Student) response.getEntity(Student.class);
System.out.println(student);
}
#Override
public URI getBaseURI() {
return UriBuilder.fromUri("http://127.0.0.1:8080/Application/student/")
.build();
}
}
I'm using this dependency:
<dependency>
<groupId>com.sun.jersey.jersey-test-framework</groupId>
<artifactId>jersey-test-framework-http</artifactId>
<version>1.2</version>
</dependency>
Student class marked as #XmlRootElement. Problem is in test class. Any ideas? Thanks for you answers
You're deploying your application to context context-path but then you're assuming (by overriding getBaseURI() method) that the application is deployed on Application context-path. Try to remove the overriding getBaseURI() method and change the test method to following:
#Test
#DatabaseSetup("dataset.xml")
public void test() throws UnsupportedEncodingException {
ClientResponse response = resource()
.path("students").path("getStudent").path("100500")
.accept(MediaType.APPLICATION_XML)
.get(ClientResponse.class);
Student student = (Student) response.getEntity(Student.class);
System.out.println(student);
}
Also check for HTTP response status (should be 200) and response media-type (should be application/xml in this case - if you request application/xml and get application/octet-stream something is clearly wrong).
using below annortation #XmlRootElement
and change library of jersey
AND server log clean after publish the project
Please check A message body writer for Java type, class myPackage.B, and MIME media type, application/octet-stream, was not found
& this link to resolve your issue.I hope it is enough to sort out your problem.
I have used Spring and Hibernate for years, but this is my first project using Spring 3 and Hibernate 4.
I set up the Model class such:
#Entity
#Table(name = "DICTIONARY_ENTRY", uniqueConstraints = #UniqueConstraint(columnNames = {
"DICTIONARY_UUID", "ANAGRAM", "WORD" }))
public class DictionaryEntry extends Pojo implements
Comparable<DictionaryEntry> {
#Column(name = "ANAGRAM", nullable = false)
private String anagram;
#Column(name = "WORD", nullable = false, unique = true)
private String word;
#Column(name = "DEFINITION", nullable = false)
private String definition;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "DICTIONARY_UUID", referencedColumnName = "UUID", nullable=false)
private Dictionary dictionary;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "fromEntry")
/*package*/ Set<CrossReference> fromReferences;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "toEntry")
/*package*/ Set<CrossReference> toReferences;
Per the directions in the Spring manual, I then set up my DAO and inject in an instance of org.springframework.orm.hibernate4.LocalSessionFactoryBean. Then I call getSession() which is:
/**
* Get the current session for a hibernate query
* #return the current session
*/
protected Session getSession(){
return sessionFactory.getCurrentSession();
}
I then run my unit test, inject in my session factory and run this method:
object = (T) getSession().save(object);
Which throws:
org.hibernate.HibernateException: No Session found for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:980)
at com.heavyweight.lexaholic.dao.hibernate.HibernateDAO.getSession(HibernateDAO.java:86)
at com.heavyweight.lexaholic.dao.hibernate.HibernateDAO.create(HibernateDAO.java:59)
at com.heavyweight.lexaholic.dao.hibernate.lexicon.DictionaryEntryHibernateDAOTest.testCRD(DictionaryEntryHibernateDAOTest.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
org.hibernate.HibernateException: No Session found for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:980)
at com.heavyweight.lexaholic.dao.hibernate.HibernateDAO.getSession(HibernateDAO.java:86)
at com.heavyweight.lexaholic.dao.hibernate.HibernateDAO.commit(HibernateDAO.java:41)
at com.heavyweight.lexaholic.dao.hibernate.lexicon.DictionaryEntryHibernateDAOTest.tearDown(DictionaryEntryHibernateDAOTest.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:37)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Here's the Spring configuration:
<bean id="testDatabase" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"><value>org.h2.Driver</value></property>
<property name="url"><value>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1</value></property>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="testDatabase"/>
</bean>
<bean id="testSessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="testDatabase" />
<property name="annotatedClasses">
<list>
<value>com.heavyweight.lexaholic.model.lexicon.CrossReference</value>
<value>com.heavyweight.lexaholic.model.lexicon.Dictionary</value>
<value>com.heavyweight.lexaholic.model.lexicon.DictionaryEntry</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.show_sql=false
hibernate.jdbc.batch_size=0
hibernate.hbm2ddl.auto=create-drop
hibernate.use_sql_comments=false
</value>
</property>
</bean>
<bean id="dictionaryEntryDAO" class="com.heavyweight.lexaholic.dao.hibernate.lexicon.DictionaryEntryHibernateDAO" init-method="init">
<property name="sessionFactory" ref="testSessionFactory" />
</bean>
There are two things you need to modify:
Firstly, you are using Hibernate for persistence, so you need to use HibernateTransactionManager instead of DataSourceTransactionManager.
<!-- Transaction Configuration For All Services (including Hibernate and MyBatis)-->
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- Transaction: enable annotation-driven transaction -->
<!--Put #Transactional on service impl instead of service interface-->
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
Secondly, you are using Hibernate 4.x, so you need to configure current session context class like this:
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext</prop>
For information, reference http://blog.springsource.org/2012/04/06/migrating-to-spring-3-1-and-hibernate-4-1/
I hope you pass it
I had the same problem in my junit test in a spring 3 application with hibernate 3.6.
When the application runs on application server, the sessions is managed with session filter:
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
But when run junit it is not loaded, you have to simulate it in your test.
One solution as suggested is to use #TransactionConfiguration or extending AbstractTransactionalJUnit4SpringContextTests but it not works if you have a Service Layer classes annotated with #Service #Transactional and you call it several times in your test.
I solved as following, according to this post:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:context.xml"})
public class JUnitTestBase extends AbstractJUnit4SpringContextTests {
#Autowired
protected Log logger;
#Autowired
protected SessionFactory sessionFactory;
protected FlushMode flushMode = FlushMode.MANUAL;
#Before
public void setUp() throws Exception {
Session session = getSession(this.sessionFactory);
TransactionSynchronizationManager.bindResource(sessionFactory,new SessionHolder(session));
logger.debug("Hibernate session is bound");
}
#After
public void tearDown() throws Exception {
SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
closeSession(sessionHolder.getSession(), sessionFactory);
logger.debug("Hibernate session is closed");
}
protected void closeSession(Session session, SessionFactory sessionFactory) {
SessionFactoryUtils.closeSession(session);
}
protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
Session session = SessionFactoryUtils.getSession(sessionFactory, true);
FlushMode flushMode = this.flushMode;
if (flushMode != null) {
session.setFlushMode(flushMode);
}
return session;
}
}
I think your test may be missing TransactionConfiguration annotation. Try the following -
#TransactionConfiguration(transactionManager="txManager")
Alternatively, you could change your bean definition for transaction manager as follows -
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="testDatabase"/>
By default spring tries to find 'transactionManager' bean.