Skip to content

Commit 95b02a9

Browse files
committed
refactor(dispatcher): use spy for all scaffolded components to avoid Dispatcher object instanciation in tests
1 parent f3be20c commit 95b02a9

5 files changed

Lines changed: 68 additions & 133 deletions

File tree

hub/dispatcher/src/test/java/com/hubsante/hub/service/DispatcherConversionErrorHandlingTest.java

Lines changed: 12 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import com.hubsante.model.edxl.EdxlMessage;
3939
import com.hubsante.model.exception.ValidationException;
4040
import io.micrometer.core.instrument.MeterRegistry;
41-
import io.micrometer.tracing.Tracer;
4241
import java.io.IOException;
4342
import java.nio.charset.StandardCharsets;
4443
import org.junit.jupiter.api.BeforeEach;
@@ -59,6 +58,7 @@ class DispatcherConversionErrorHandlingTest {
5958
private MessagePersistenceService persistenceService;
6059
private HubConfiguration hubConfig;
6160
private ClientPropertiesRegistry clientPropertiesRegistry;
61+
private Validator validator;
6262
private EdxlHandler edxlHandler;
6363
private XmlMapper xmlMapper;
6464
private ObjectMapper jsonMapper;
@@ -74,6 +74,7 @@ void setUp() {
7474
persistenceService = hub.persistenceService();
7575
hubConfig = hub.hubConfig();
7676
clientPropertiesRegistry = hub.clientPropertiesRegistry();
77+
validator = hub.validator();
7778
edxlHandler = hub.edxlHandler();
7879
xmlMapper = hub.xmlMapper();
7980
jsonMapper = hub.jsonMapper();
@@ -87,19 +88,6 @@ public void shouldHandleConversionServiceError() throws IOException {
8788
// sdisC -> samuV3 on vhost 15-nexsis_v1.9 => transcoding triggered
8889
doReturn(NEXSIS_VHOST).when(hubConfig).getVhost();
8990

90-
MessageHandler messageHandlerSpy = spy(messageHandler);
91-
Dispatcher testDispatcher =
92-
new Dispatcher(
93-
messageHandlerSpy,
94-
rabbitTemplate,
95-
edxlHandler,
96-
xmlMapper,
97-
jsonMapper,
98-
conversionHandler,
99-
hubConfig,
100-
persistenceService,
101-
Tracer.NOOP);
102-
10391
Message receivedMessage =
10492
createMessage("EDXL-DE", JSON, SDIS_C_ROUTING_KEY, SAMU_V3_ROUTING_KEY);
10593
EdxlMessage edxlMessage =
@@ -113,13 +101,13 @@ public void shouldHandleConversionServiceError() throws IOException {
113101

114102
assertThrows(
115103
AmqpRejectAndDontRequeueException.class,
116-
() -> testDispatcher.dispatch(receivedMessage));
104+
() -> dispatcher.dispatch(receivedMessage));
117105

118106
ArgumentCaptor<ConversionException> exceptionCaptor =
119107
ArgumentCaptor.forClass(ConversionException.class);
120108
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
121109

122-
verify(messageHandlerSpy).handleError(exceptionCaptor.capture(), messageCaptor.capture());
110+
verify(messageHandler).handleError(exceptionCaptor.capture(), messageCaptor.capture());
123111

124112
ConversionException thrownException = exceptionCaptor.getValue();
125113
assertEquals(
@@ -133,42 +121,16 @@ public void shouldHandleConversionServiceError() throws IOException {
133121
@Test
134122
@DisplayName("should transfer to another vhost when an error is raised after message transfer")
135123
public void transferErrorToOtherVhost() throws IOException, ValidationException {
136-
ClientPropertiesRegistry clientPropertiesRegistrySpy =
137-
Mockito.spy(clientPropertiesRegistry);
138-
doReturn(clientPropertiesRegistrySpy).when(hubConfig).getClientPropertiesRegistry();
139124
doReturn("15-15_v2.0").when(hubConfig).getVhost();
140125
doReturn(new String[] {"1.5"})
141-
.when(clientPropertiesRegistrySpy)
126+
.when(clientPropertiesRegistry)
142127
.getClientVersionsForPerimeter(SAMU_A_ROUTING_KEY, "15-15");
143-
Validator validatorMock = Mockito.mock(Validator.class);
144-
Mockito.doThrow(
128+
doThrow(
145129
new SchemaValidationException(
146130
"Mock schema validation error", "mock_distribution_id"))
147-
.when(validatorMock)
131+
.when(validator)
148132
.validateJSON(anyString(), any());
149133

150-
MessageHandler messageHandlerSpy =
151-
new MessageHandler(
152-
rabbitTemplate,
153-
edxlHandler,
154-
hubConfig,
155-
validatorMock,
156-
registry,
157-
xmlMapper,
158-
jsonMapper,
159-
conversionHandler);
160-
Dispatcher dispatcherSpy =
161-
new Dispatcher(
162-
messageHandlerSpy,
163-
rabbitTemplate,
164-
edxlHandler,
165-
xmlMapper,
166-
jsonMapper,
167-
conversionHandler,
168-
hubConfig,
169-
persistenceService,
170-
Tracer.NOOP);
171-
172134
Message message = createMessage("EDXL-DE", JSON, SAMU_V1_ROUTING_KEY, SAMU_A_ROUTING_KEY);
173135

174136
String exchangeName = "transfer_15-15_v2.0_to_15-15_v1.5";
@@ -177,7 +139,7 @@ public void transferErrorToOtherVhost() throws IOException, ValidationException
177139
AmqpRejectAndDontRequeueException errorThrown =
178140
assertThrows(
179141
AmqpRejectAndDontRequeueException.class,
180-
() -> dispatcherSpy.dispatch(message));
142+
() -> dispatcher.dispatch(message));
181143

182144
assertEquals("Mock schema validation error", errorThrown.getCause().getMessage());
183145

@@ -197,50 +159,24 @@ public void sendErrorMessageToSameVhost() throws IOException {
197159
@Test
198160
@DisplayName("should send error message to sender info queue when error is raised")
199161
public void sendErrorMessageWhenErrorIsRaised() throws IOException, ValidationException {
200-
ClientPropertiesRegistry clientPropertiesRegistrySpy =
201-
Mockito.spy(clientPropertiesRegistry);
202-
doReturn(clientPropertiesRegistrySpy).when(hubConfig).getClientPropertiesRegistry();
203162
doReturn("15-15_v1.5").when(hubConfig).getVhost();
204163
doReturn(new String[] {"1.5"})
205-
.when(clientPropertiesRegistrySpy)
164+
.when(clientPropertiesRegistry)
206165
.getClientVersionsForPerimeter(SAMU_A_ROUTING_KEY, "15-15");
207166
// Default hub vhost is v2.1 and samuA declares v2.1: validation error is forwarded directly
208167
// to samuA's info queue without any conversion.
209-
Validator validatorMock = Mockito.mock(Validator.class);
210-
Mockito.doThrow(
168+
doThrow(
211169
new SchemaValidationException(
212170
"Mock schema validation error", "mock_distribution_id"))
213-
.when(validatorMock)
171+
.when(validator)
214172
.validateJSON(anyString(), any());
215173

216-
MessageHandler messageHandlerSpy =
217-
new MessageHandler(
218-
rabbitTemplate,
219-
edxlHandler,
220-
hubConfig,
221-
validatorMock,
222-
registry,
223-
xmlMapper,
224-
jsonMapper,
225-
conversionHandler);
226-
Dispatcher dispatcherSpy =
227-
new Dispatcher(
228-
messageHandlerSpy,
229-
rabbitTemplate,
230-
edxlHandler,
231-
xmlMapper,
232-
jsonMapper,
233-
conversionHandler,
234-
hubConfig,
235-
persistenceService,
236-
Tracer.NOOP);
237-
238174
Message message = createMessage("EDXL-DE", JSON);
239175

240176
AmqpRejectAndDontRequeueException errorThrown =
241177
assertThrows(
242178
AmqpRejectAndDontRequeueException.class,
243-
() -> dispatcherSpy.dispatch(message));
179+
() -> dispatcher.dispatch(message));
244180

245181
assertEquals("Mock schema validation error", errorThrown.getCause().getMessage());
246182

hub/dispatcher/src/test/java/com/hubsante/hub/service/DispatcherConversionRoutingTest.java

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import com.hubsante.hub.utils.*;
3838
import com.hubsante.model.EdxlHandler;
3939
import com.hubsante.model.edxl.EdxlMessage;
40-
import io.micrometer.tracing.Tracer;
4140
import java.io.IOException;
4241
import java.nio.charset.StandardCharsets;
4342
import org.junit.jupiter.api.BeforeEach;
@@ -236,19 +235,6 @@ public void sendToTransferExchange() throws IOException {
236235
@Test
237236
@DisplayName("should call sendToTransferExchange when there is a version conversion")
238237
public void transferToOtherVhost() throws IOException {
239-
Dispatcher dispatcher =
240-
spy(
241-
new Dispatcher(
242-
messageHandler,
243-
rabbitTemplate,
244-
edxlHandler,
245-
xmlMapper,
246-
jsonMapper,
247-
conversionHandler,
248-
hubConfig,
249-
persistenceService,
250-
Tracer.NOOP));
251-
252238
Message message = createMessage("EDXL-DE", JSON, SAMU_A_ROUTING_KEY, SAMU_V1_ROUTING_KEY);
253239

254240
dispatcher.dispatch(message);

hub/dispatcher/src/test/java/com/hubsante/hub/service/DispatcherMessageValidationTest.java

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
import com.hubsante.model.EdxlHandler;
3535
import com.hubsante.model.edxl.EdxlMessage;
3636
import com.hubsante.model.report.ErrorCode;
37-
import io.micrometer.tracing.Tracer;
3837
import java.io.IOException;
3938
import java.nio.charset.StandardCharsets;
4039
import java.util.*;
@@ -259,17 +258,6 @@ public void checkMessageClassNameSupportedDoesNotThrow() throws Exception {
259258
edxlMessage.getFirstContentMessage()))
260259
.thenReturn(supportedClassName);
261260

262-
new Dispatcher(
263-
messageHandler,
264-
rabbitTemplate,
265-
edxlHandler,
266-
xmlMapper,
267-
jsonMapper,
268-
conversionHandler,
269-
hubConfig,
270-
persistenceService,
271-
Tracer.NOOP);
272-
273261
assertDoesNotThrow(
274262
() -> MessageUtils.checkMessageClassNameSupported(edxlMessage, hubConfig));
275263
}
@@ -296,17 +284,6 @@ public void checkMessageClassNameSupportedThrowsException() throws Exception {
296284
edxlMessage.getFirstContentMessage()))
297285
.thenReturn(unsupportedClassName);
298286

299-
new Dispatcher(
300-
messageHandler,
301-
rabbitTemplate,
302-
edxlHandler,
303-
xmlMapper,
304-
jsonMapper,
305-
conversionHandler,
306-
hubConfig,
307-
persistenceService,
308-
Tracer.NOOP);
309-
310287
UnroutableMessageException thrown =
311288
assertThrows(
312289
UnroutableMessageException.class,

hub/dispatcher/src/test/java/com/hubsante/hub/testsupport/HubTestScaffolding.java

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public Hub build() {
8686
MeterRegistry registry = new SimpleMeterRegistry();
8787

8888
ClientPropertiesRegistry clientPropertiesRegistry =
89-
new ClientPropertiesRegistry(new ClassPathResource(CLIENTS_YAML));
89+
spy(new ClientPropertiesRegistry(new ClassPathResource(CLIENTS_YAML)));
9090
// TopologyRegistry publishes itself through a static field read by ConversionUtils and
9191
// MessagePersistencePolicy: in production Spring builds it, here the scaffolding must.
9292
new TopologyRegistry(new ClassPathResource(CLIENTS_YAML));
@@ -96,29 +96,32 @@ public Hub build() {
9696
MessagePersistenceService persistenceService = mock(MessagePersistenceService.class);
9797
ConversionHandler conversionHandler =
9898
spy(new ConversionHandler(mock(WebClient.class), edxlHandler));
99+
Validator validator = spy(new Validator());
99100

100101
MessageHandler messageHandler =
101-
new MessageHandler(
102-
rabbitTemplate,
103-
edxlHandler,
104-
hubConfig,
105-
new Validator(),
106-
registry,
107-
xmlMapper,
108-
jsonMapper,
109-
conversionHandler);
102+
spy(
103+
new MessageHandler(
104+
rabbitTemplate,
105+
edxlHandler,
106+
hubConfig,
107+
validator,
108+
registry,
109+
xmlMapper,
110+
jsonMapper,
111+
conversionHandler));
110112

111113
Dispatcher dispatcher =
112-
new Dispatcher(
113-
messageHandler,
114-
rabbitTemplate,
115-
edxlHandler,
116-
xmlMapper,
117-
jsonMapper,
118-
conversionHandler,
119-
hubConfig,
120-
persistenceService,
121-
Tracer.NOOP);
114+
spy(
115+
new Dispatcher(
116+
messageHandler,
117+
rabbitTemplate,
118+
edxlHandler,
119+
xmlMapper,
120+
jsonMapper,
121+
conversionHandler,
122+
hubConfig,
123+
persistenceService,
124+
Tracer.NOOP));
122125

123126
return new Hub(
124127
dispatcher,
@@ -128,6 +131,7 @@ public Hub build() {
128131
persistenceService,
129132
hubConfig,
130133
clientPropertiesRegistry,
134+
validator,
131135
edxlHandler,
132136
xmlMapper,
133137
jsonMapper,
@@ -170,6 +174,7 @@ public record Hub(
170174
MessagePersistenceService persistenceService,
171175
HubConfiguration hubConfig,
172176
ClientPropertiesRegistry clientPropertiesRegistry,
177+
Validator validator,
173178
EdxlHandler edxlHandler,
174179
XmlMapper xmlMapper,
175180
ObjectMapper jsonMapper,

hub/dispatcher/src/test/java/com/hubsante/hub/testsupport/HubTestScaffoldingTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.junit.jupiter.api.DisplayName;
3232
import org.junit.jupiter.api.Test;
3333
import org.mockito.ArgumentCaptor;
34+
import org.mockito.internal.util.MockUtil;
3435
import org.springframework.amqp.core.Message;
3536
import org.springframework.amqp.core.MessageProperties;
3637

@@ -44,6 +45,36 @@ class HubTestScaffoldingTest {
4445
private static final String XML = MessageProperties.CONTENT_TYPE_XML;
4546
private static final String SAMU_B_MESSAGE_QUEUE = "fr.health.samuB.message";
4647

48+
/**
49+
* Every collaborator a test may stub or verify must be a mock or a spy, and must be the very
50+
* instance wired into the graph. A plain instance here sends tests back to rebuilding the graph
51+
* by hand, and a spy that is not the wired one fails silently — it simply never records a call.
52+
*/
53+
@Test
54+
@DisplayName("should expose stubbable collaborators, wired into the graph")
55+
void shouldExposeStubbableCollaborators() {
56+
HubTestScaffolding.Hub hub = aHub().build();
57+
58+
assertThat(MockUtil.isMock(hub.dispatcher())).as("dispatcher is a spy").isTrue();
59+
assertThat(MockUtil.isMock(hub.messageHandler())).as("messageHandler is a spy").isTrue();
60+
assertThat(MockUtil.isMock(hub.conversionHandler()))
61+
.as("conversionHandler is a spy")
62+
.isTrue();
63+
assertThat(MockUtil.isMock(hub.hubConfig())).as("hubConfig is a spy").isTrue();
64+
assertThat(MockUtil.isMock(hub.clientPropertiesRegistry()))
65+
.as("clientPropertiesRegistry is a spy")
66+
.isTrue();
67+
assertThat(MockUtil.isMock(hub.validator())).as("validator is a spy").isTrue();
68+
assertThat(MockUtil.isMock(hub.rabbitTemplate())).as("rabbitTemplate is a mock").isTrue();
69+
assertThat(MockUtil.isMock(hub.persistenceService()))
70+
.as("persistenceService is a mock")
71+
.isTrue();
72+
73+
assertThat(hub.hubConfig().getClientPropertiesRegistry())
74+
.as("hubConfig must hand out the same registry the tests stub")
75+
.isSameAs(hub.clientPropertiesRegistry());
76+
}
77+
4778
@Test
4879
@DisplayName("should wire every collaborator of the dispatcher graph")
4980
void shouldWireTheWholeGraph() {

0 commit comments

Comments
 (0)