I'm using mockito/powermock version 1.7.0, Spring Boot 2.0.0 M2, Kotlin 1.3.0.
I'm testing a Spring #Service class, that inject a Repository.
I want to mock that repository on my tests, so I can just test the class itself.
I'm new to Kotlin, but I come from Java, so I tried doing this "the java way", but probably I'm missing something...
Here is my Service interface:
interface MyService {
fun create(myObject: MyObject): MyObject
}
... and its implementation:
#Service
class DefaultMyService : MyService {
#Autowired
lateinit var myRepository: MyRepository
override fun create(myObject: MyObject): MyObject = this.myRepository.insert(myObject)
}
Here is my repository (I'm using Spring Data with Mongo):
interface MyRepository: MongoRepository<MyObject, String>
Here is my test class:
#RunWith(PowerMockRunner::class)
#PrepareForTest(MyService::class)
class MyServiceTest {
#Mock
lateinit var myRepository: MyRepository
#InjectMocks
lateinit var myService: MyService
#Test
fun shouldDoSomething() {
val myObject = MyObject(name = "Marco")
`when`(myRepository.insert(myObject)).thenReturn(myObject)
assertEquals(myObject.name, this.myService.create(myObject).name)
}
}
When I run this test, an exception occurs:
Exception in thread "main" java.lang.NoClassDefFoundError: org/mockito/exceptions/Reporter
at sun.reflect.GeneratedSerializationConstructorAccessor5.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:48)
at org.powermock.reflect.internal.WhiteboxImpl.newInstance(WhiteboxImpl.java:260)
at org.powermock.reflect.Whitebox.newInstance(Whitebox.java:139)
at org.powermock.api.extension.reporter.AbstractMockingFrameworkReporterFactory.getInstanceForClassLoader(AbstractMockingFrameworkReporterFactory.java:41)
at org.powermock.api.extension.reporter.AbstractMockingFrameworkReporterFactory.create(AbstractMockingFrameworkReporterFactory.java:35)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.getMockingFrameworkReporter(JUnit4TestSuiteChunkerImpl.java:140)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:119)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:57)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.ClassNotFoundException: org.mockito.exceptions.Reporter
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.powermock.core.classloader.MockClassLoader.loadModifiedClass(MockClassLoader.java:202)
at org.powermock.core.classloader.DeferSupportingClassLoader.loadClass1(DeferSupportingClassLoader.java:89)
at org.powermock.core.classloader.DeferSupportingClassLoader.loadClass(DeferSupportingClassLoader.java:79)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 16 more
What am I doing wrong? I think it's an issue with some configuration, but I can't understand exactly where the mistake is.
It seems like that your mockito and powermock versions are not working very well together. You have to use versions which are compatible. See the compatibility matrix of powermock https://github.com/powermock/powermock/wiki/Mockito#supported-versions
Latest compatible is Mockito: 2.8.x with PowerMock: 1.7.0
Related
I have the following conditional class that should be unseen unless some other class annotates itself with a custom annotation:
#ConditionalOnBean(MyConf.class)
#Service
#RequiredArgsConstructor
public class CondClass{
public void method() throws MessagingException
Then I have a spring boot test:
#SpringBootTest
public void myTest{
It works fine if I manually execute it, but if I do:
mvn clean package
I get:
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: java.lang.IllegalStateException: Failed to introspect Class
[it.bmed.medmad.arch.common.websocket.service.impl.CondClass] from ClassLoader
[sun.misc.Launcher$AppClassLoader#18b4aac2]
Caused by: java.lang.NoClassDefFoundError: org/springframework/messaging/MessagingException
Caused by: java.lang.ClassNotFoundException:
org.springframework.messaging.MessagingException
Indeed that MessagingException is on a dependency that is not included, but I would expect that the whole class is not inspected because of the annotation.
Add #ConditionalOnClass(MyConf.class), too:
#ConditionalOnClass(MyConf.class)
#ConditionalOnBean(MyConf.class)
#Service
#RequiredArgsConstructor
public class CondClass {
// ...
}
sample: official usage
I have a spring-boot app in development using kotlin - overall things are going well. (spring 1.5.6.RELEASE, kotlin 1.1.4-3)
Anyway, I was adding my first controller test after reviewing some example code, and am running into this annoying error:
kotlin.UninitializedPropertyAccessException: lateinit property restTemplate has not been initialized
kotlin.UninitializedPropertyAccessException: lateinit property testRestTemplate has not been initialized
at com.thingy.controllers.ProductSetControllerTest.getTestRestTemplate(ProductSetControllerTest.kt:16)
at com.thingy.controllers.ProductSetControllerTest.testGet(ProductSetControllerTest.kt:20)
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.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
at org.testng.TestRunner.privateRun(TestRunner.java:767)
at org.testng.TestRunner.run(TestRunner.java:617)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
at org.testng.SuiteRunner.run(SuiteRunner.java:240)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1198)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1123)
at org.testng.TestNG.run(TestNG.java:1031)
at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:72)
at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:123)
Here's the test class
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.web.client.TestRestTemplate
import org.springframework.test.context.junit4.SpringRunner
import org.testng.Assert
import org.testng.annotations.Test
#RunWith(SpringRunner::class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ProductSetControllerTest {
#Autowired
lateinit var restTemplate: TestRestTemplate
#Test
fun testGet() {
val forObject = restTemplate.getForObject("/", String::class.java)
Assert.assertEquals(forObject, "gettest")
}
}
Some addl things I've tried:
- ensured I'm not using deprecated TestRestTemplate
- tried using setter injection instead of field injection, but was a waste of time.
- disabled kotlin compiler plugins
Spring Boot does not automatically instantiate TestRestTemplate bean(duh!).
You need to define it yourself and then you will be able to use it.
#Bean
open fun restTemplate(): TestRestTemplate {
return TestRestTemplate()
}
I'm trying to get simple example of springboot and camel working but come undone. Not sure what i'm doing wrong. in the gradle build i've included so far
dependencies {
compile 'org.apache.camel:camel-spring-boot-starter:2.18.4'
compile 'org.apache.camel:camel-groovy:2.18.4'
compile 'org.apache.camel:camel-stream:2.18.4'
compile 'org.codehaus.groovy:groovy-all:2.4.11'
testCompile group: 'junit', name: 'junit', version: '4.11'
testCompile group: 'junit', name: 'junit', version: '4.12'
}
i've create a DirectRoute component like this
#Component
class DirectRoute extends RouteBuilder{
#Override
void configure () throws Exception {
from ("direct:in") //tried stream:in also
.to ("stream:out")
}
}
I then have a driver bean that try's to invoke the route
#Component
public class HelloImpl implements Hello {
#Produce(uri = "direct:in")
private ProducerTemplate template;
#Override
public String say(String value) throws ExecutionException, InterruptedException {
assert template
println "def endpoint is : " + template.getDefaultEndpoint()
return template.sendBody (template.getDefaultEndpoint(), value)
}
}
lastly in the springboot application class i added a command line runner like this, that gets my bean from the spring context, and invokes the say method. I'm using groovy so i just passed a closure to the command line runner.
#Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
//return closure to run on startup - just list the beans enabled
{args ->
println("Let's inspect the beans provided by Spring Boot:")
String[] beanNames = ctx.getBeanDefinitionNames()
Arrays.sort(beanNames)
for (String beanName : beanNames) {
println(beanName)
}
println("call the direct:start route via the service")
Hello service = ctx.getBean("helloService")
def result = service.say("William")
println "service returned : $result "
}
}
when i run my application i get all the bean names printed out (that's ok), however when i invoke the direct:in via producer template i get this error (org.apache.camel.component.direct.DirectConsumerNotAvailableException) see below.
I was expecting the route to be triggered the name sent to see that arrive in the output stream - but this is what i get.
Caused by: org.apache.camel.CamelExecutionException: Exception occurred during execution on the exchange: Exchange[ID-MONSTER-PC2-58911-1496920205300-0-2]
at org.apache.camel.util.ObjectHelper.wrapCamelExecutionException(ObjectHelper.java:1795) ~[camel-core-2.18.4.jar:2.18.4]
at org.apache.camel.util.ExchangeHelper.extractResultBody(ExchangeHelper.java:677) ~[camel-core-2.18.4.jar:2.18.4]
at org.apache.camel.impl.DefaultProducerTemplate.extractResultBody(DefaultProducerTemplate.java:515) ~[camel-core-2.18.4.jar:2.18.4]
at org.apache.camel.impl.DefaultProducerTemplate.extractResultBody(DefaultProducerTemplate.java:511) ~[camel-core-2.18.4.jar:2.18.4]
at org.apache.camel.impl.DefaultProducerTemplate.sendBody(DefaultProducerTemplate.java:163) ~[camel-core-2.18.4.jar:2.18.4]
at org.apache.camel.ProducerTemplate$sendBody$0.call(Unknown Source) ~[na:na]
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) [groovy-all-2.4.11.jar:2.4.11]
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113) [groovy-all-2.4.11.jar:2.4.11]
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133) [groovy-all-2.4.11.jar:2.4.11]
at services.HelloImpl.say(HelloImpl.groovy:29) ~[main/:na]
at services.Hello$say.call(Unknown Source) ~[na:na]
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) [groovy-all-2.4.11.jar:2.4.11]
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113) [groovy-all-2.4.11.jar:2.4.11]
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125) [groovy-all-2.4.11.jar:2.4.11]
at application.Application$_commandLineRunner_closure1.doCall(Application.groovy:47) ~[main/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_121]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_121]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_121]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_121]
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93) ~[groovy-all-2.4.11.jar:2.4.11]
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325) ~[groovy-all-2.4.11.jar:2.4.11]
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294) ~[groovy-all-2.4.11.jar:2.4.11]
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022) ~[groovy-all-2.4.11.jar:2.4.11]
at groovy.lang.Closure.call(Closure.java:414) ~[groovy-all-2.4.11.jar:2.4.11]
at org.codehaus.groovy.runtime.ConvertedClosure.invokeCustom(ConvertedClosure.java:54) ~[groovy-all-2.4.11.jar:2.4.11]
at org.codehaus.groovy.runtime.ConversionHandler.invoke(ConversionHandler.java:124) ~[groovy-all-2.4.11.jar:2.4.11]
at com.sun.proxy.$Proxy44.run(Unknown Source) ~[na:na]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:776) [spring-boot-1.5.2.RELEASE.jar:1.5.2.RELEASE]
... 10 common frames omitted
Caused by: org.apache.camel.component.direct.DirectConsumerNotAvailableException: No consumers available on endpoint: direct://in. Exchange[ID-MONSTER-PC2-58911-1496920205300-0-2]
at org.apache.camel.component.direct.DirectProducer.process(DirectProducer.java:55) ~[camel-core-2.18.4.jar:2.18.4]
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:197) ~[camel-core-2.18.4.jar:2.18.4]
at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:97) ~[camel-core-2.18.4.jar:2.18.4]
at org.apache.camel.impl.ProducerCache$1.doInProducer(ProducerCache.java:529) ~[camel-core-2.18.4.jar:2.18.4]
at org.apache.camel.impl.ProducerCache$1.doInProducer(ProducerCache.java:497) ~[camel-core-2.18.4.jar:2.18.4]
at org.apache.camel.impl.ProducerCache.doInProducer(ProducerCache.java:365) ~[camel-core-2.18.4.jar:2.18.4]
at org.apache.camel.impl.ProducerCache.sendExchange(ProducerCache.java:497) ~[camel-core-2.18.4.jar:2.18.4]
at org.apache.camel.impl.ProducerCache.send(ProducerCache.java:225) ~[camel-core-2.18.4.jar:2.18.4]
at org.apache.camel.impl.DefaultProducerTemplate.send(DefaultProducerTemplate.java:144) ~[camel-core-2.18.4.jar:2.18.4]
at org.apache.camel.impl.DefaultProducerTemplate.sendBody(DefaultProducerTemplate.java:161) ~[camel-core-2.18.4.jar:2.18.4]
What have i done wrong - and why does the producer template invocation on 'direct:in' (also tried stream in with same problem) not work? I thought that .to("stream:out") would be a consumer.
any pointers or advice gratefully received at this point
I have an update on my problems:
I had a subpackage with the application class annotated with #SpringBootApplication. So yes, unadorned it only scans subpackages.
you can add scanBasePackages= or scanBaseClasses= parameter, however when I tried doing a scan for single class, it seemed to scan the whole directory any way and grabbed the others as well.
I refactored the app to have a single root package with subpackages and elected to set the 'scanBasePakages to the new root package. but left the Application class in its own subpackage (personal preference only - documentation suggests leaving the Application in the root package)
you can now add other classes annotated with #Configuration to generate beans or use the basic #Component.
if you create Camel routes annotated with #Component they will be auto configured in the camelContext for you.
it appears by default that Spring isnt not starting the camelContext for you. When I checked the status of the context it shows as starting and not started. so in my commandLineRunner I had to start get the spring injected camelContext and had to start it myself, and exited it when I finished. I was slightly suprised as I thought SpringBootStarter would auto start the camelContext, but it appears not.
once you have Spring component scanning etc working and you start the camelContext, then problems with the org.apache.camel.component.direct.DirectConsumerNotAvailableException exception went away and things started to work - at least the baby examples I'm trying.
So revised structure now looks like this:
The revised ApplicationClass now looks like this with some simple println output to see the state of the context, and beans in the spring ctx. The helleoService bean is still the proxy I use to setup the producer template to call the DirectRoute.
package com.softwood.application
import groovy.util.logging.Slf4j
import org.apache.camel.CamelContext
import org.springframework.beans.factory.annotation.Autowired
import com.softwood.services.Hello
/**
* Created by willw on 07/06/2017.
*/
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean
#Slf4j //inject logger
#SpringBootApplication (scanBasePackages = ["com.softwood"]) //forces scan at parent
// same as #Configuration #EnableAutoConfiguration #ComponentScan with 'defaults' e.g. sub packages
public class Application {
#Autowired
ApplicationContext ctx
#Autowired
CamelContext camelContext
public static void main(String[] args) {
SpringApplication.run(Application.class, args)
}
#Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
//return closure to run on startup - just list the beans enabled
{args ->
println("Let's inspect the beans provided by Spring Boot:")
String[] beanNames = ctx.getBeanDefinitionNames()
Arrays.sort(beanNames)
for (String beanName : beanNames) {
println(beanName)
}
/* when component scan is working - bean routes are added
automatically to camel context via springBoot, however you do have to start
the camel context, yourself
*/
println "camelCtx has following components : " + camelContext.componentNames
println "camelCtx state is : " + camelContext.status
println "starting camel context"
camelContext.start()
println "camelCtx state now is : " + camelContext.status
//log.debug "wills logging call "
println("call the direct:start route via the service")
Hello service = ctx.getBean("helloService")
def result = service.say("William")
println "service returned : $result "
println "sleep 5 seconds "
sleep (5000)
println "stop camel context"
camelContext.stop()
println "camelCtx state now is : " + camelContext.status
}
}
}
That proxy is just registered as a simple bean like this in the spring context
package com.softwood.services
/**
* Created by willw on 07/06/2017.
*/
import org.apache.camel.Produce;
import org.apache.camel.ProducerTemplate
import org.springframework.stereotype.Component;
import java.util.concurrent.ExecutionException
#Component
public class HelloImpl implements Hello {
#Produce(uri = "direct:in") /* ?block=true */
private ProducerTemplate template
#Override
public String say(String value) throws ExecutionException, InterruptedException {
assert template
println "def endpoint is : " + template.getDefaultEndpoint()
//Future future = template.asyncSendBody(template.getDefaultEndpoint(), value)
//return future.get()
return template.sendBody (template.getDefaultEndpoint(), value)
}
}
The TimedRoute just sorts itself out with no template required to invoke in
package com.softwood.camelRoutes
/**
* Created by willw on 07/06/2017.
*/
import org.apache.camel.builder.RouteBuilder
import org.springframework.stereotype.Component
#Component
class TimedRoute extends RouteBuilder {
#Override
void configure () throws Exception {
from ("timer:foo")
.to ("log:com.softwood.application.Application?level=WARN")
}
}
My simple no-op file route isn't working (yet) and not sure why. I suspect I've not got the file config right somehow; some playing is required.
package com.softwood.camelRoutes
import org.apache.camel.builder.RouteBuilder
import org.springframework.stereotype.Component
/**
* Created by willw on 08/06/2017.
*/
#Component
class FileNoOpRoute extends RouteBuilder{
#Override
void configure () throws Exception {
from ("file:../com.softwood.file-inbox?recursive=true&noop=true&idempotent=true")
.to ("file:../com.softwood.file-outbox")
}
}
However the basics are not working and least camel is doing something whereas before I just had the exception and nothing.
I have found another question on Spring config highlighting some of the above also.
I am having hard time with JerseyTest and Spring. Previously in non-Spring Java projects what I usually did for my REST APIs was to extend my Test from JerseyTest, mocking the Service classes and simply (unit)testing my REST API. Now I'm using spring in my project where in my REST resource classes the Services are annotated with #Autowired. Now that I'm using the same scenario. Spring jumps in and nags about stuff like lack of applicationcontext.xml. I do want to use spring in my production but for my unit test I don't need my test know anything about Spring and all its autowiring and classpath annotation processing! How can I get this right? The classes look like this:
public class RESTResource{
#Autowired
MyService service;
#GET
public Response getSomeStuff(){
...
service.getStuff()
}
}
And here is the Test class
public class RESTResourceTest extends JerseyTest{
private Service service;
#Override
public Application configure(){
RESTResource resource = new RESTResource();
service = Mockito.mock(Service.class);
resource.setService(service);
ResourceConfig config = new ResourceConfig();
config.register(resource);
return config;
}
}
This is the stacktrace:
org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [applicationContext.xml]; nested exception is java.io.FileNotFoundException: class path resource [applicationContext.xml] cannot be opened because it does not exist
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:344)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:181)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:217)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:252)
at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:127)
at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:93)
at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:129)
at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:538)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:452)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
at org.glassfish.jersey.server.spring.SpringComponentProvider.createXmlSpringConfiguration(SpringComponentProvider.java:173)
at org.glassfish.jersey.server.spring.SpringComponentProvider.createSpringContext(SpringComponentProvider.java:164)
at org.glassfish.jersey.server.spring.SpringComponentProvider.initialize(SpringComponentProvider.java:99)
at org.glassfish.jersey.server.ApplicationHandler$4.get(ApplicationHandler.java:408)
at org.glassfish.jersey.server.ApplicationHandler$4.get(ApplicationHandler.java:399)
at org.glassfish.jersey.internal.util.collection.Values$LazyValueImpl.get(Values.java:340)
at org.glassfish.jersey.server.ApplicationHandler$3.call(ApplicationHandler.java:350)
at org.glassfish.jersey.server.ApplicationHandler$3.call(ApplicationHandler.java:347)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.processWithException(Errors.java:255)
at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:347)
at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:299)
at org.glassfish.jersey.test.inmemory.InMemoryTestContainerFactory$InMemoryTestContainer.<init>(InMemoryTestContainerFactory.java:77)
at org.glassfish.jersey.test.inmemory.InMemoryTestContainerFactory$InMemoryTestContainer.<init>(InMemoryTestContainerFactory.java:63)
at org.glassfish.jersey.test.inmemory.InMemoryTestContainerFactory.create(InMemoryTestContainerFactory.java:111)
at org.glassfish.jersey.test.JerseyTest.createTestContainer(JerseyTest.java:277)
at org.glassfish.jersey.test.JerseyTest.setUp(JerseyTest.java:609)
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:497)
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.RunBefores.evaluate(RunBefores.java:24)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
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.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
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)
Caused by: java.io.FileNotFoundException: class path resource [applicationContext.xml] cannot be opened because it does not exist
at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:172)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:330)
... 56 more
P.S. I'm using spring boot.
What you can do is to simply exclude the jersey-spring3 using the the sure-fire plugin for test phase.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<classpathDependencyExcludes>
<classpathDependencyExclude>
org.glassfish.jersey.ext:jersey-spring3
</classpathDependencyExclude>
</classpathDependencyExcludes>
</configuration>
</plugin>
Here is some code snippets that might help in your case :
Option 1. Your REST resource class :
#Component
#Path("/api/helloworld")
public class RESTResource{
#Autowired
MyService service;
#GET
#Produces(MediaType.TEXT_PLAIN)
public String helloMessage() {
return "Hello World Jersey Way!";
}
}
Your test config class :
#Component
public class JerseyConfig extends ResourceConfig {
/**
* In constructor we can define Jersey Resources & Other Components
*/
public JerseyConfig() {
register(RESTResource.class);
}
}
3.Your test base class :
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)//NOTE : Application is a spring boot main class,or if you have specific configuration class similar to test config class above use #ContextConfiguration(classes = MyServiceSpringConfig.class)
public class RESTResourceTest extends JerseyTest {
#Override
protected Application configure() {
return new JerseyConfig();
}
#Test
public void contextLoads() {
}
#Test
public void someTest() throws Exception {
// Very useful test
}
}
Option 2 :
#Priority(value = 1)
public class MySpringWebInitializer implements WebApplicationInitializer
{
#Override
public void onStartup(ServletContext container)
{
//Tell jersey-spring3 the context is already initialized
container.setInitParameter("contextConfigLocation", "NOTNULL");
AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
appContext.register(RESTResource.class);
container.addListener(new ContextLoaderListener(appContext));
}
}
Also,for spring boot you can run test cases using an active profile or a config name ,pass runtime VM args with -Dspring.config.name=test for running test cases etc..
Hope this help and the rest is self explanatory.
The better way to integrate JerseyTest with Spring
No inheritance from JerseyTest in junit test class
No dependencies on Jersey in junit test class, just pure jax-rs dependency
perfectly integrate SpringJUnit4ClassRunner and #ContextConfiguration
My solution is hosted on github. Hope this help for you.
Why is my spring test set up failing with the following not-so-useful error messages below? All suggestions are appreciated.
JUnit Output
java.lang.NoClassDefFoundError: org/junit/runners/model/MultipleFailureException
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.withAfterClasses(SpringJUnit4ClassRunner.java:188)
at org.junit.runners.ParentRunner.classBlock(ParentRunner.java:145)
at org.junit.runners.ParentRunner.run(ParentRunner.java:235)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run (SpringJUnit4ClassRunner.java:163)
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: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)
Caused by: java.lang.ClassNotFoundException: org.junit.runners.model.MultipleFailureException
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 10 more
Console Output
INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Could not instantiate TestExecutionListener [org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [org/springframework/transaction/interceptor/TransactionAttribute]
INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Could not instantiate TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [org/springframework/transaction/interceptor/TransactionAttributeSource]
INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener#76959acc, org.springframework.test.context.support.DependencyInjectionTestExecutionListener#57e603e6, org.springframework.test.context.support.DirtiesContextTestExecutionListener#3e0a1e1f]
Here is the target snippet
#Service
public class PipApps {
#Resource( name = "apps" )
private Properties apps;
#Autowired
private SitePreferenceHandler sitePreferenceHandler;
#Autowired
private PipsTable pipsTable;
private SitePreference sitePreference;
private Device device;
public PipApps( HttpServletRequest request, HttpServletResponse response ){
sitePreference = sitePreferenceHandler.handleSitePreference( request, response );
device = DeviceUtils.getRequiredCurrentDevice( request );
}
public Properties getApps(){
return apps;
}
public Device getDevice(){
return device;
}
public SitePreference getSitePreference(){
return sitePreference;
}
public DeviceRouteTable getPipsTable(){
return pipsTable;
}
}
And the test snippet
#RunWith( SpringJUnit4ClassRunner.class )
#ContextConfiguration( locations={"src/test/resources/PipAppsTest-context.xml"} )
public class PipAppsTest {
#Mock
SitePreferenceHandler sitePreferenceHandler;
#Autowired
PipApps pipApps;
...
}
Update -- September 2015
Spring Framework 4.2.2 throws a more meaningful exception if JUnit 4.9 is not in the classpath. See SPR-13521 for details.
The following is an excerpt from the class-level Javadoc for SpringJUnit4ClassRunner:
NOTE: As of Spring Framework 4.1, this class requires JUnit 4.9 or higher.
The class in question, MultipleFailureException, was introduced in JUnit 4.9.
So that's why your test is failing with the ClassNotFoundException.
Upgrading to JUnit 4.9 (or preferably 4.12) will therefore solve your problem.
Regards,
Sam (author of the Spring TestContext Framework)