使用场景:
当项目引入了Spring之后,进行单元测试时,如果需要使用到一些类,可以利用Spring的对象管理功能,不用再自己new对象出来。
Step1
在测试类加入如下两个注解,使得Junit支持Spring IOC
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {“classpath*:spring/spring.xml”}) //*可加可不加
- 不要忘记在你的Spring上下文ApplicationContext.xml中加入component-scan,如下:
<context:component-scan base-package="com.paic.health"/>
- Note:配置ContextConfiguration时要注意classpath要写对,不然Spring找不到classpath,无法扫描组件。报错如下:
16:27:34,282 [main] ERROR [TestContextManager] Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@56ac3a89] to prepare test instance [com.paic.mhis.health.component.TaskTest@370736d9]
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.paic.mhis.health.component.TaskTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.paic.mhis.health.component.Task com.paic.mhis.health.component.TaskTest.task; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.paic.mhis.health.component.Task] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:385)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:228)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:230)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:249)
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.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: org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.paic.mhis.health.component.Task com.paic.mhis.health.component.TaskTest.task; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.paic.mhis.health.component.Task] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
... 25 more
Sample:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring/spring.xml"})
public class TaskTest {
@Autowired
Task task;
// Task task = new Task();
@Test
public void test() throws Exception{
long start = System.currentTimeMillis();
Future<String> task1 = task.doTaskOne();
Future<String> task2 = task.doTaskTwo();
Future<String> task3 = task.doTaskThree();
while (true) {
if (task1.isDone() && task2.isDone() && task3.isDone()) {
break;
}
Thread.sleep(1000);
}
long end = System.currentTimeMillis();
System.out.println("all task end,耗时:" + (end -start) + "毫秒");
}
}
Step2
将需要注入的类加上@Component注解,like this
@Component
public class Task {
public static Random random = new Random();
@Async
public Future<String> doTaskOne() throws Exception {
System.out.println("task one start");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
System.out.println("task one end,耗时:" + (end -start) + "毫秒");
return new AsyncResult<>("task1 end");
}
@Async
public Future<String> doTaskTwo() throws Exception {
System.out.println("task two start");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
System.out.println("task two end,耗时:" + (end -start) + "毫秒");
return new AsyncResult<>("task2 end");
}
@Async
public Future<String> doTaskThree() throws Exception {
System.out.println("task three start");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
System.out.println("task three end,耗时:" + (end -start) + "毫秒");
return new AsyncResult<>("task3 end");
}
}
Step3
测试类种使用@Autowired将Task的对象注入进来,like this
public class TaskTest {
@Autowired
Task task;
// Task task = new Task();
@Test
public void test() throws Exception{
long start = System.currentTimeMillis();
Future<String> task1 = task.doTaskOne();
Future<String> task2 = task.doTaskTwo();
Future<String> task3 = task.doTaskThree();
while (true) {
if (task1.isDone() && task2.isDone() && task3.isDone()) {
break;
}
Thread.sleep(1000);
}
long end = System.currentTimeMillis();
System.out.println("all task end,耗时:" + (end -start) + "毫秒");
}
}
Step4 测试结果
通过测试,Junit完美注入了Task对象,不用再进行new操作。