Testing is a crucial part of developing a robust jPOS client. It ensures that your ISO-8583 message creation, sending, and processing work correctly. We'll cover various aspects of testing, including unit tests, integration tests, and simulating server responses.
Unit tests are essential for testing individual components of your jPOS client. Let's start with a simple example of testing a message creation service.
import org.jpos.iso.ISOMsg;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class MessageCreationServiceTest {
@Mock
private ISOFactory isoFactory;
@InjectMocks
private MessageCreationService messageCreationService;
@Test
void testCreateAuthorizationRequest() throws Exception {
// Arrange
ISOMsg mockMsg = new ISOMsg();
when(isoFactory.createMsg("0100")).thenReturn(mockMsg);
// Act
ISOMsg result = messageCreationService.createAuthorizationRequest("1234567890123456", 100.00);
// Assert
assertThat(result).isNotNull();
assertThat(result.getMTI()).isEqualTo("0100");
assertThat(result.getString(2)).isEqualTo("1234567890123456");
assertThat(result.getString(4)).isEqualTo("000000010000");
}
}In this example, we're testing the MessageCreationService class, which is responsible for creating ISO-8583 messages. We use Mockito to mock the ISOFactory and AssertJ for fluent assertions.
Integration tests ensure that different components of your jPOS client work together correctly. Here's an example of an integration test that sends a message and verifies the response:
import org.jpos.iso.ISOMsg;
import org.jpos.iso.MUX;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
public class TransactionSenderIntegrationTest {
@Autowired
private MUX mux;
@Autowired
private MessageCreationService messageCreationService;
@Test
void testSendAuthorizationRequest() throws Exception {
// Arrange
ISOMsg request = messageCreationService.createAuthorizationRequest("1234567890123456", 100.00);
// Act
ISOMsg response = mux.request(request, 30000);
// Assert
assertThat(response).isNotNull();
assertThat(response.getMTI()).isEqualTo("0110");
assertThat(response.getString(39)).isEqualTo("00"); // Assuming '00' is approval code
}
}This integration test creates an authorization request, sends it through the MUX, and verifies the response. It uses the actual Spring context, so it's closer to real-world scenarios.
To test various scenarios without relying on an actual server, we can use Wiremock to simulate server responses. Here's an example of how to set up a Wiremock server to simulate ISO-8583 responses:
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import org.jpos.iso.ISOMsg;
import org.jpos.iso.channel.NACChannel;
import org.jpos.iso.packager.GenericPackager;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.assertj.core.api.Assertions.assertThat;
public class ISOClientWiremockTest {
private WireMockServer wireMockServer;
private NACChannel channel;
@BeforeEach
void setup() throws Exception {
wireMockServer = new WireMockServer(WireMockConfiguration.options().port(8888));
wireMockServer.start();
GenericPackager packager = new GenericPackager("packager/iso87ascii.xml");
channel = new NACChannel("localhost", 8888, packager);
channel.connect();
}
@AfterEach
void teardown() {
channel.disconnect();
wireMockServer.stop();
}
@Test
void testAuthorizationRequest() throws Exception {
// Arrange
String responseHex = "30313130F23C46D129E09180000000000000001000000000000010000301000000301000012345678901234560000";
wireMockServer.stubFor(any(urlEqualTo("/"))
.willReturn(aResponse()
.withStatus(200)
.withBody(hexStringToByteArray(responseHex))));
// Act
ISOMsg request = new ISOMsg();
request.setMTI("0100");
request.set(2, "1234567890123456");
request.set(4, "000000010000");
ISOMsg response = channel.send(request);
// Assert
assertThat(response).isNotNull();
assertThat(response.getMTI()).isEqualTo("0110");
assertThat(response.getString(39)).isEqualTo("00");
}
private byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
}This test sets up a Wiremock server to simulate an ISO-8583 server. It stubs a response for any incoming request and then sends a request using the NACChannel. The test verifies that the response is correctly parsed and contains the expected data.
jPOS provides a Q2 container that can be useful for testing. Here's an example of how to set up a test using Q2:
import org.jpos.q2.Q2;
import org.jpos.q2.iso.QMUX;
import org.jpos.util.NameRegistrar;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class Q2Test {
private static Q2 q2;
@BeforeAll
static void setup() throws Exception {
q2 = new Q2();
q2.start();
Thread.sleep(2000); // Wait for Q2 to start
}
@AfterAll
static void teardown() {
q2.stop();
}
@Test
void testQMUX() throws Exception {
QMUX qmux = (QMUX) NameRegistrar.get("mux.mymux");
assertThat(qmux).isNotNull();
assertThat(qmux.isConnected()).isTrue();
ISOMsg msg = new ISOMsg("0800");
msg.set(11, "000001");
msg.set(70, "301");
ISOMsg response = qmux.request(msg, 30000);
assertThat(response).isNotNull();
assertThat(response.getMTI()).isEqualTo("0810");
assertThat(response.getString(39)).isEqualTo("00");
}
}This test starts a Q2 instance, retrieves a QMUX from the NameRegistrar, and sends a network management request. It then verifies the response.
For performance testing, you might want to simulate multiple concurrent requests. Here's a simple example using Java's ExecutorService:
import org.jpos.iso.ISOMsg;
import org.jpos.iso.MUX;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
public class PerformanceTest {
@Autowired
private MUX mux;
@Autowired
private MessageCreationService messageCreationService;
@Test
void testConcurrentRequests() throws Exception {
int numRequests = 100;
ExecutorService executor = Executors.newFixedThreadPool(10);
List<Future<ISOMsg>> futures = new ArrayList<>();
for (int i = 0; i < numRequests; i++) {
futures.add(executor.submit(() -> {
ISOMsg request = messageCreationService.createAuthorizationRequest("1234567890123456", 100.00);
return mux.request(request, 30000);
}));
}
for (Future<ISOMsg> future : futures) {
ISOMsg response = future.get();
assertThat(response).isNotNull();
assertThat(response.getMTI()).isEqualTo("0110");
assertThat(response.getString(39)).isEqualTo("00");
}
executor.shutdown();
}
}This test simulates 100 concurrent authorization requests and verifies that all responses are successful.