使用 Spring Boot 在 Activiti 中为 JUnit 测试构建 ApplicationContext 时出现异常
Exception when building the ApplicationContext for a JUnit test in Activiti with Spring Boot
每当我尝试 运行 使用 Spring Boot 对 Activiti 进行以下 JUnit 测试时,我都无法解决以下异常。
异常:
2015-05-07 20:15:00 org.springframework.test.context.TestContext.<init>(93@main) INFO @ContextConfiguration not found for class [class ProcessXTest].
2015-05-07 20:15:00 org.springframework.test.context.TestContextManager.retrieveTestExecutionListeners(143@main) INFO @TestExecutionListeners is not present for class [class ProcessXTest]: using defaults.
2015-05-07 20:15:00 org.springframework.test.context.TestContextManager.prepareTestInstance(234@main) ERROR Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@232023ff] to prepare test instance [ProcessXTest@131b4c5d]
java.lang.IllegalArgumentException: Can not build an ApplicationContext with a NULL 'contextLoader'. Consider annotating your test class with @ContextConfiguration.
JUnit 测试:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { Application.class })
public class ProcessXTest {
private static final Logger LOGGER = LoggerFactory.getLogger(ProcessXTest.class);
private static final String BPMN_LOCATION = "./src/main/resources/processes/processx.bpmn";
private static final String BPMN_NAME = "processx.bpmn";
private static final String PROCESS_KEY = "processx";
@Rule
public ActivitiRule activitiRule = new ActivitiRule();
@Before
public void loadProces() throws FileNotFoundException {
LOGGER.debug("Loading the model for unit testing.");
RepositoryService repositoryService = activitiRule.getRepositoryService();
Deployment deployment = repositoryService.createDeployment().addInputStream(BPMN_NAME, new FileInputStream(BPMN_LOCATION)).deploy();
assertNotNull(deployment.getId());
assertTrue(repositoryService.getDeploymentResourceNames(deployment.getId()).contains(bpmnName));
}
@Test
public void testProces() {
LOGGER.debug("Unit testing the process.");
TaskService taskService = activitiRule.getTaskService();
List<Task> tasks = taskService.createTaskQuery().list();
assertEquals(tasks.size(), 0);
ProcessInstance processInstance = activitiRule.getRuntimeService().startProcessInstanceByKey(PROCESS_KEY, new HashMap<String, Object>());
assertNotNull(processInstance.getId());
tasks = taskService.createTaskQuery().list();
assertEquals(tasks.size(), 1);
}
}
主应用程序 class(所有 bean 都在此 class 中定义,因此没有使用外部 XML 上下文配置文件):
@SpringBootApplication
@EnableConfigurationProperties
public class Application {
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public CommandLineRunner init() {
return new CommandLineRunner() {
@Override
public void run(final String... strings) throws Exception {
// initialization on start-up
}
};
}
...more beans
}
我正在使用以下依赖项:
compile 'org.activiti:activiti-engine:5.17.0'
compile 'org.activiti:spring-boot-starter-basic:5.17.0'
compile 'org.activiti:spring-boot-starter-rest-api:5.17.0'
compile 'junit:junit:4.12'
compile 'org.springframework.boot:spring-boot-starter-web:1.2.3.RELEASE'
compile 'org.springframework.boot:spring-boot-starter-test:1.2.3.RELEASE'
我终于通过如下定义 JUnit 测试解决了这个问题:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { Application.class })
public class ProcessXTest {
private static final Logger LOGGER = LoggerFactory.getLogger(ProcessXTest.class);
private static final String BPMN_LOCATION = "./src/main/resources/processes/processx.bpmn";
private static final String BPMN_NAME = "processx.bpmn";
private static final String PROCESS_KEY = "processx";
@Autowired
private RepositoryService repositoryService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Autowired
private HistoryService historyService;
@Before
public void loadModel() throws FileNotFoundException {
LOGGER.debug("Loading the model for unit testing.");
Deployment deployment = repositoryService.createDeployment().addInputStream(BPMN_NAME, new FileInputStream(BPMN_LOCATION)).deploy();
assertNotNull(deployment.getId());
assertTrue(repositoryService.getDeploymentResourceNames(deployment.getId()).contains(bpmnName));
}
@Test
public void testProcess() {
LOGGER.debug("Unit testing the process.");
List<Task> tasks = taskService.createTaskQuery().list();
assertEquals(tasks.size(), 0);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(PROCESS_KEY, new HashMap<String, Object>());
assertNotNull(processInstance.getId());
tasks = taskService.createTaskQuery().list();
assertEquals(tasks.size(), 1);
}
}
考虑到 @ActivitiRule 默认使用类路径上的 activiti.cfg.xml 资源初始化 ProcessEgine,我不得不修改我的 JUnit 测试:http://activiti.org/javadocs/org/activiti/engine/test/ActivitiRule.html
我的解决方案:
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.test.ActivitiRule;
import org.activiti.spring.boot.AbstractProcessEngineConfiguration;
import org.junit.Rule;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(AbstractSpringTest.ActivitiEngineTestConfiguration.class)
@ActiveProfiles("test")
public abstract class AbstractSpringTest {
@Autowired @Rule
public ActivitiRule activitiRule;
@SpringBootApplication
public static class ActivitiEngineTestConfiguration {
@Bean
public ActivitiRule activitiRule(ProcessEngine processEngine) {
return new ActivitiRule(processEngine);
}
}
}
有一个文件 application-test.properties 包含(在此示例中使用 h2):
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:activiti?characterEncoding=UTF-8
spring.datasource.username=sa
spring.datasource.password=sa
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.show-sql=true
AbstractSpringTest 的每个子类都可以使用例如@Deployment:
public class ConcreteTest extends AbstractSpringTest {
@Test
@Deployment(resources = {"processes/test_process.bpmn20.xml"})
public void testSomething() {
}
}
每当我尝试 运行 使用 Spring Boot 对 Activiti 进行以下 JUnit 测试时,我都无法解决以下异常。
异常:
2015-05-07 20:15:00 org.springframework.test.context.TestContext.<init>(93@main) INFO @ContextConfiguration not found for class [class ProcessXTest].
2015-05-07 20:15:00 org.springframework.test.context.TestContextManager.retrieveTestExecutionListeners(143@main) INFO @TestExecutionListeners is not present for class [class ProcessXTest]: using defaults.
2015-05-07 20:15:00 org.springframework.test.context.TestContextManager.prepareTestInstance(234@main) ERROR Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@232023ff] to prepare test instance [ProcessXTest@131b4c5d]
java.lang.IllegalArgumentException: Can not build an ApplicationContext with a NULL 'contextLoader'. Consider annotating your test class with @ContextConfiguration.
JUnit 测试:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { Application.class })
public class ProcessXTest {
private static final Logger LOGGER = LoggerFactory.getLogger(ProcessXTest.class);
private static final String BPMN_LOCATION = "./src/main/resources/processes/processx.bpmn";
private static final String BPMN_NAME = "processx.bpmn";
private static final String PROCESS_KEY = "processx";
@Rule
public ActivitiRule activitiRule = new ActivitiRule();
@Before
public void loadProces() throws FileNotFoundException {
LOGGER.debug("Loading the model for unit testing.");
RepositoryService repositoryService = activitiRule.getRepositoryService();
Deployment deployment = repositoryService.createDeployment().addInputStream(BPMN_NAME, new FileInputStream(BPMN_LOCATION)).deploy();
assertNotNull(deployment.getId());
assertTrue(repositoryService.getDeploymentResourceNames(deployment.getId()).contains(bpmnName));
}
@Test
public void testProces() {
LOGGER.debug("Unit testing the process.");
TaskService taskService = activitiRule.getTaskService();
List<Task> tasks = taskService.createTaskQuery().list();
assertEquals(tasks.size(), 0);
ProcessInstance processInstance = activitiRule.getRuntimeService().startProcessInstanceByKey(PROCESS_KEY, new HashMap<String, Object>());
assertNotNull(processInstance.getId());
tasks = taskService.createTaskQuery().list();
assertEquals(tasks.size(), 1);
}
}
主应用程序 class(所有 bean 都在此 class 中定义,因此没有使用外部 XML 上下文配置文件):
@SpringBootApplication
@EnableConfigurationProperties
public class Application {
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public CommandLineRunner init() {
return new CommandLineRunner() {
@Override
public void run(final String... strings) throws Exception {
// initialization on start-up
}
};
}
...more beans
}
我正在使用以下依赖项:
compile 'org.activiti:activiti-engine:5.17.0'
compile 'org.activiti:spring-boot-starter-basic:5.17.0'
compile 'org.activiti:spring-boot-starter-rest-api:5.17.0'
compile 'junit:junit:4.12'
compile 'org.springframework.boot:spring-boot-starter-web:1.2.3.RELEASE'
compile 'org.springframework.boot:spring-boot-starter-test:1.2.3.RELEASE'
我终于通过如下定义 JUnit 测试解决了这个问题:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { Application.class })
public class ProcessXTest {
private static final Logger LOGGER = LoggerFactory.getLogger(ProcessXTest.class);
private static final String BPMN_LOCATION = "./src/main/resources/processes/processx.bpmn";
private static final String BPMN_NAME = "processx.bpmn";
private static final String PROCESS_KEY = "processx";
@Autowired
private RepositoryService repositoryService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Autowired
private HistoryService historyService;
@Before
public void loadModel() throws FileNotFoundException {
LOGGER.debug("Loading the model for unit testing.");
Deployment deployment = repositoryService.createDeployment().addInputStream(BPMN_NAME, new FileInputStream(BPMN_LOCATION)).deploy();
assertNotNull(deployment.getId());
assertTrue(repositoryService.getDeploymentResourceNames(deployment.getId()).contains(bpmnName));
}
@Test
public void testProcess() {
LOGGER.debug("Unit testing the process.");
List<Task> tasks = taskService.createTaskQuery().list();
assertEquals(tasks.size(), 0);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(PROCESS_KEY, new HashMap<String, Object>());
assertNotNull(processInstance.getId());
tasks = taskService.createTaskQuery().list();
assertEquals(tasks.size(), 1);
}
}
考虑到 @ActivitiRule 默认使用类路径上的 activiti.cfg.xml 资源初始化 ProcessEgine,我不得不修改我的 JUnit 测试:http://activiti.org/javadocs/org/activiti/engine/test/ActivitiRule.html
我的解决方案:
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.test.ActivitiRule;
import org.activiti.spring.boot.AbstractProcessEngineConfiguration;
import org.junit.Rule;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(AbstractSpringTest.ActivitiEngineTestConfiguration.class)
@ActiveProfiles("test")
public abstract class AbstractSpringTest {
@Autowired @Rule
public ActivitiRule activitiRule;
@SpringBootApplication
public static class ActivitiEngineTestConfiguration {
@Bean
public ActivitiRule activitiRule(ProcessEngine processEngine) {
return new ActivitiRule(processEngine);
}
}
}
有一个文件 application-test.properties 包含(在此示例中使用 h2):
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:activiti?characterEncoding=UTF-8
spring.datasource.username=sa
spring.datasource.password=sa
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.show-sql=true
AbstractSpringTest 的每个子类都可以使用例如@Deployment:
public class ConcreteTest extends AbstractSpringTest {
@Test
@Deployment(resources = {"processes/test_process.bpmn20.xml"})
public void testSomething() {
}
}