0

I would like to mock the JMS connection factory to do integration testing.

<jee:jndi-lookup id="narconFactory" jndi-name="LBARQCF" resource-ref="false"/>

when (?)

we use websphere server, and for intyegration testing need to use tomcat. Spring boot version is 1.5.3

EDIT: Based on comments, I created a class

@RunWith(SpringRunner.class)
@SpringBootTest
public class MQControllerTest {

//step 2
@Autowired
private MockMvc mvc;

@MockBean
private MQController mqController;

protected static final ConnectionFactory amqFactory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false");

public static final CachingConnectionFactory connectionFactory = new CachingConnectionFactory(amqFactory);

@BeforeClass
public static void startUp() throws Exception {
    connectionFactory.setCacheConsumers(false);
    connectionFactory.createConnection().close();
}

@AfterClass
public static void shutDown() {
    connectionFactory.resetConnection();
}

@Autowired
private JmsTemplate mockJmsTemplate;

@Autowired
private SourcePollingChannelAdapter startJms;


@Before
public void setup() throws JMSException{
    Mockito.reset(this.mockJmsTemplate);
}   

@Test
public void test_tbm_vrijeDagenCorrectie() throws Exception {

    String expectedResponse ="";
    //using bddmockito
    given(mqController.tmVDCorrect(any(String.class))).willReturn(expectedResponse);

    this.startJms.start();

    mvc.perform(get("/tm/vdc/{dgn}","2016-01-16"))
               .andExpect(status().isOk());

}

}

In my resources - config file ** edit*** used full package name and made connectionFactory as public

    <util:constant id="narconFactory" static-field="n.d.poc.MQControllerTest.connectionFactory"/>
     <util:constant id="vanconFactory" static-field="n.d.poc.MQControllerTest.connectionFactory"/> 

Error:

No qualifying bean of type 'org.springframework.test.web.servlet.MockMvc' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1474) ~[spring-beans-4.3.5.RELEASE.jar:4.3.5.RELEASE]

Not sure whats my mistake EDIT2:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'narconFactory': Invocation of init method failed; nested exception is javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:742) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866) ~[spring-context-4.3.8.RELEASE.jar:4.3.8.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542) ~[spring-context-4.3.8.RELEASE.jar:4.3.8.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:737) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:370) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE] at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120) ~[spring-boot-test-1.5.3.RELEASE.jar:1.5.3.RELEASE] at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98) ~[spring-test-4.3.8.RELEASE.jar:4.3.8.RELEASE] at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116) ~[spring-test-4.3.8.RELEASE.jar:4.3.8.RELEASE] ... 27 common frames omitted

why unit testing is looking for java.naming.factory.initial? can I provide in application properties and with what value?

EDIT3:

sample code in github https://github.com/kswat/LRIntegrationUnit

Kris Swat
  • 788
  • 1
  • 10
  • 39

1 Answers1

1

I would suggest to consider to use ActiveMQ with its embedded mode instead of mocking. This way you'll get the fully blown JMS and won't deal with low-level resources to also mock.

In Spring Integration we have this for testing purpose:

/**
 * Keeps an ActiveMQ {@link VMTransport} open for the duration of
 * all tests (avoids cycling the transport each time the last
 * connection is closed).
 * @author Gary Russell
 * @since 3.0
 *
 */
public abstract class ActiveMQMultiContextTests {

    protected static final ConnectionFactory amqFactory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false");

    protected static final CachingConnectionFactory connectionFactory = new CachingConnectionFactory(
            amqFactory);

    @BeforeClass
    public static void startUp() throws Exception {
        connectionFactory.setCacheConsumers(false);
        connectionFactory.createConnection().close();
    }

    @AfterClass
    public static void shutDown() {
        connectionFactory.resetConnection();
    }

}

That connectionFactory static property indeed can be used as a bean:

<util:constant id="narconFactory"
               static-field="ActiveMQMultiContextTests.connectionFactory"/>
Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • You need to copy/paste the content of that class - it is indeed in the test and not publicly available. Although source code is on GitHub : https://github.com/spring-projects/spring-integration/blob/master/spring-integration-jms/src/test/java/org/springframework/integration/jms/ActiveMQMultiContextTests.java – Artem Bilan May 24 '18 at 11:16
  • ok thanks. can I create a file like that in any package? Do I need to make it non-abstract? – Kris Swat May 24 '18 at 14:20
  • Yes, of course. The point is that you need to have those ` @BeforeClass` and `@AfterClass` available for your target JUnit tests. – Artem Bilan May 24 '18 at 14:23
  • I think your mistake there that you are missing package alongside with the class name in the `` definition. – Artem Bilan May 25 '18 at 18:33
  • Try to make that field as `public` – Artem Bilan May 29 '18 at 11:39
  • Thanks. I am getting another error - Caused by: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:662) ~[na:1.8.0_112]. I can add entry to application.properties, but what should be the value? not sure how to reolsve this. – Kris Swat May 30 '18 at 09:10
  • This JNDI error is fully not related to the topic here – Artem Bilan May 30 '18 at 11:53
  • I think in your config somewhere you still have a `narconFactory` bean which looks into the JNDI.Try to place a config for tests beans *after* the normal one. This way you will override this `narconFactory` with that constant for the ActiveMQ `ConnectionFactory` – Artem Bilan Jun 01 '18 at 13:43
  • I have followed example from github - GatewayDemoTest example, when I converted to integration test, it is failing with error - java.naming.factory.initial.though I stripped code to bare minimum. – Kris Swat Jun 04 '18 at 17:13
  • There is no any JNDI in that sample. I believe there is something else in your config. Would be great if you can share a simple project on GH to let us to play locally and figure out what and how tried to connection via JNDI. – Artem Bilan Jun 04 '18 at 17:14
  • Code added in github. unit test was giving null pointer initially, but after increasing timeout, it is working. Integration test is not working – Kris Swat Jun 08 '18 at 12:47
  • Well, not sure what is with your unit test, but `queueReceiver.receive(3000)` really might not be enough to get a message over JMS. We use in our test a magic number as `10 secs`. – Artem Bilan Jun 08 '18 at 13:02
  • In your IT test you have a problem that you load a normal application context wirh those JNDI configuration. See how `@SpringBootTest` works. You later `new GenericXmlApplicationContext()` – Artem Bilan Jun 08 '18 at 13:03
  • In your IT test you have a problem that you load a normal application context wirh those JNDI configuration. See how `@SpringBootTest` works. You later `new GenericXmlApplicationContext()` does not make sense there already and doesn't override anything from the main application context. You need to consider to add this testing `bvr-config.xml` into the main application context facet via this `@TestConfiguration` annotation: https://docs.spring.io/spring-boot/docs/2.0.2.RELEASE/reference/htmlsingle/#boot-features-testing-spring-boot-applications. I mean apply similar `@ImportResource` – Artem Bilan Jun 08 '18 at 13:09