2

I am not able to solve the below exception whenever I try to run the below JUnit test for Activiti with Spring Boot.

Exception:

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 test:

@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);
    }
}

Main application class (all beans are defined in this class and for this reason no external XML context configuration file is used):

@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
}

I am using the below dependencies:

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'
Christophe
  • 113
  • 3
  • 14
  • Did you try annotating your test class with @ContextConfiguration? – mattias May 07 '15 at 20:35
  • Adding this annotations returns the following exception: `2015-05-07 22:41:57 org.springframework.test.context.TestContextManager.prepareTestInstance(234@main) ERROR Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@367cca66] to prepare test instance [ProcessXTest@3acc0a7c] exception is java.io.FileNotFoundException: class path resource [ProcessXTest-context.xml] cannot be opened because it does not exist` – Christophe May 07 '15 at 20:42
  • So do you have a contextconfiguration xml at the place it is trying to find it? Have a look at for example http://stackoverflow.com/questions/4377699/spring-contextconfiguration-how-to-put-the-right-location-for-the-xml or https://spring.io/blog/2011/06/21/spring-3-1-m2-testing-with-configuration-classes-and-profiles. It seems you can also try the @Configuration annotation. – mattias May 07 '15 at 20:47
  • Yes, I was able to bypass the exception by introducing an XML context configuration file (with no beans defined). This however gives a null-pointer on `repositoryService.createDeployment()` when running the test. I prefer not to use any external XML context configuration file as all the beans have already been defined in the main application class. – Christophe May 08 '15 at 07:27

2 Answers2

1

My solution:

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);
        }
    }
}

Have a file application-test.properties containing (using h2 in this example):

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

Each subclass of AbstractSpringTest can then use for example @Deployment:

public class ConcreteTest extends AbstractSpringTest {

    @Test
    @Deployment(resources = {"processes/test_process.bpmn20.xml"})
    public void testSomething() {
    }
}
0

I finally solved it by defining the JUnit test as follow:

@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);
    }
}

I had to revise my JUnit test taking into account that the @ActivitiRule initializes the ProcessEgine by using the activiti.cfg.xml resource on the classpath as a default: http://activiti.org/javadocs/org/activiti/engine/test/ActivitiRule.html

Christophe
  • 113
  • 3
  • 14