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.
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.