Search code examples
javaibm-mq

Unit Test IBM MQ


I'm new at the MQ topic.

How do I Test/Unit-Test my Java Services, which do actions against a real Queue. My classes do connections, deletes etc.

Is there any way to test these services without performing actions against the productive Queues?

@Service
public class QueueConnectionService {

    private final MQConfigMapping configMapping;

    private MQQueueManager queueManager;

    @Autowired
    public QueueConnectionService(MQConfigMapping configMapping) {
        this.configMapping = configMapping;
    }


    MQQueue connect(String queuePropertyTitle, int openOptions, String queueName) throws MQException {
        MQEnvironment.hostname = configMapping.getNamed().get(queuePropertyTitle).getHostname();
        MQEnvironment.channel = configMapping.getNamed().get(queuePropertyTitle).getChannel();
        MQEnvironment.port = configMapping.getNamed().get(queuePropertyTitle).getPort();
        MQEnvironment.userID = configMapping.getNamed().get(queuePropertyTitle).getUser();
        MQEnvironment.password = configMapping.getNamed().get(queuePropertyTitle).getPassword();
        queueManager = new MQQueueManager(configMapping.getNamed().get(queuePropertyTitle).getQueueManager());
        return queueManager.accessQueue(queueName, openOptions);
    }
}

This is my QueueConnectionService, but I have no clue how to use this one at local tests.


Solution

  • In order to do unit tests, you will need to mock the IBM MQ classes, using a framework like Mockito.

    One issue you'll encounter is that you cannot mock the call to the MQQueueManager constructor, as the new operator cannot be mocked. I would recommend creating a MqQueueManagerFactory service, autowire this service into your QueueConnectionService and mock it in the test.

    Your unit test will end up looking like this:

    @ExtendWith(MockitoExtension.class)
    class QueueConnectionServiceTest {
    
      private static final String TITLE = "Some random string";
      private static final String QUEUE_MANAGER = "Actual value does not matter";
      private static final String NAME = "Really. Those constants are magic strings.";
      private static final int OPTIONS = 42;
    
      @InjectMock
      private QueueConnectionService service;
    
      @Mock(answer = RETURNS_DEEP_STUBS)
      private MQConfigMapping configMapping;
    
      @Mock
      private MqConnectionManagerFactory connectionManagerFactory;
    
      @Mock
      private MQConnectionManager connectionManager;
    
      @Mock
      private MQQueue queue;
    
      @Test
      void should_provide_queue() {
        when(configMapping.getNamed().get(TITLE).getQueueManager()).thenReturn(QUEUE_MANAGER);
        // repeat above line for each configuration parameter.
        // Alternatively, create a config object and:
        when(configMapping.getNamed().get(TITLE)).thenReturn(config);
    
        when(connectionManagerFactory.create(QUEUE_MANAGER)).thenReturn(connectionManager);
        when(connectionManager.accessQueue(NAME, OPTIONS)).thenReturn(queue);
    
        var actual = service.connect(TITLE, OPTIONS, NAME);
    
        assertSame(actual, queue);
      }
    
    }
    

    (This is with JUnit 5 and Mockito. You would have something slightly different with another testing framework or another mocking framework.)

    As a side note, creating a queue manager at each connection smells bad. You probably want to create it once in an @PostConstruct method.