matcher = MatcherFactory
+ .usingIgnoringFieldsComparator("id");
+
+ matcher.assertMatch(moneyMarketSecurityResult, moneyMarketSecurityPrediction);
+
+ System.out.println("Ok");
+ setIsUsed(true);
+
+ synchronized (waiter) {
+ waiter.notify();
+ }
+ }, true);
+
+ startService();
+
+ synchronized (waiter) {
+ waiter.wait(TIMEOUT);
+ }
+
+ Assertions.assertEquals(true, isUsed);
+ iMap.removeEntryListener(listenerID);
+ }
+
+}
diff --git a/clearing-parent/securities-service/src/test/java/ru/spcex/clearing/securities/utils/MatcherFactory.java b/clearing-parent/securities-service/src/test/java/ru/spcex/clearing/securities/utils/MatcherFactory.java
new file mode 100644
index 000000000..63bd29dab
--- /dev/null
+++ b/clearing-parent/securities-service/src/test/java/ru/spcex/clearing/securities/utils/MatcherFactory.java
@@ -0,0 +1,38 @@
+package ru.spcex.clearing.securities.utils;
+
+import java.util.Arrays;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Factory for creating test matchers.
+ *
+ * Comparing actual and expected objects via AssertJ
+ */
+public class MatcherFactory {
+
+ public static Matcher usingIgnoringFieldsComparator(String... fieldsToIgnore) {
+ return new Matcher<>(fieldsToIgnore);
+ }
+
+ public static class Matcher {
+ private final String[] fieldsToIgnore;
+
+ private Matcher(String... fieldsToIgnore) {
+ this.fieldsToIgnore = fieldsToIgnore;
+ }
+
+ public void assertMatch(T actual, T expected) {
+ assertThat(actual).usingRecursiveComparison().ignoringFields(fieldsToIgnore).isEqualTo(expected);
+ }
+
+ @SafeVarargs
+ public final void assertMatch(Iterable actual, T... expected) {
+ assertMatch(actual, Arrays.asList(expected));
+ }
+
+ public void assertMatch(Iterable actual, Iterable expected) {
+ assertThat(actual).usingRecursiveFieldByFieldElementComparatorIgnoringFields(fieldsToIgnore).isEqualTo(expected);
+ }
+ }
+}
\ No newline at end of file
diff --git a/clearing-parent/utility-service/src/test/java/ru/spcex/clearing/utility/config/HazelcastInstanceTestConfiguration.java b/clearing-parent/utility-service/src/test/java/ru/spcex/clearing/utility/config/HazelcastInstanceTestConfiguration.java
new file mode 100644
index 000000000..148e3e29b
--- /dev/null
+++ b/clearing-parent/utility-service/src/test/java/ru/spcex/clearing/utility/config/HazelcastInstanceTestConfiguration.java
@@ -0,0 +1,23 @@
+package ru.spcex.clearing.utility.config;
+
+import com.hazelcast.client.HazelcastClient;
+import com.hazelcast.config.Config;
+import com.hazelcast.config.JoinConfig;
+import com.hazelcast.config.MulticastConfig;
+import com.hazelcast.config.NetworkConfig;
+import com.hazelcast.core.Hazelcast;
+import com.hazelcast.core.HazelcastInstance;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Random;
+
+@Configuration
+public class HazelcastInstanceTestConfiguration {
+
+ @Bean(name = "hazelcastInstance")
+ public HazelcastInstance hazelcastInstance() {
+ return HazelcastClient.newHazelcastClient();
+ }
+
+}
\ No newline at end of file
diff --git a/clearing-parent/utility-service/src/test/java/ru/spcex/clearing/utility/config/HazelcastServiceTestConfiguration.java b/clearing-parent/utility-service/src/test/java/ru/spcex/clearing/utility/config/HazelcastServiceTestConfiguration.java
new file mode 100644
index 000000000..d1cfc84d0
--- /dev/null
+++ b/clearing-parent/utility-service/src/test/java/ru/spcex/clearing/utility/config/HazelcastServiceTestConfiguration.java
@@ -0,0 +1,73 @@
+package ru.spcex.clearing.utility.config;
+
+import com.hazelcast.config.*;
+import com.hazelcast.core.Hazelcast;
+import com.hazelcast.core.HazelcastInstance;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import ru.spcex.platform.imdg.iml.hazelcast.config.HazelcastClientParams;
+import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
+import ru.spcex.platform.imdg.iml.hazelcast.util.HazelcastHelper;
+
+import java.util.List;
+import java.util.Random;
+
+@Configuration
+public class HazelcastServiceTestConfiguration {
+ private HazelcastInstance hazelcastInstance;
+
+ private static ThreadPoolTaskExecutor createThreadPoolTaskExecutor(int maxPoolSz, boolean waitForCompletion) {
+ ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
+ if (maxPoolSz > 2) {
+ pool.setKeepAliveSeconds(60);
+ pool.setAllowCoreThreadTimeOut(true);
+ }
+ pool.setCorePoolSize(maxPoolSz);
+ pool.setWaitForTasksToCompleteOnShutdown(waitForCompletion);
+ return pool;
+ }
+
+ @Bean(name = "hazelcastServiceTest")
+ public HazelcastService hazelcastService(@Qualifier("taskExecutorHazelcastClientInitializer") ThreadPoolTaskExecutor taskExecutorHazelcastClientInitializer, @Qualifier("taskExecutorIdGeneratorAwaiter") ThreadPoolTaskExecutor taskExecutorIdGeneratorAwaiter, HazelcastClientParams params) {
+ Config cfg = new Config();
+ cfg.setInstanceName("localhost");
+
+ NetworkConfig networkConfig = new NetworkConfig();
+ JoinConfig joinConfig = new JoinConfig();
+ joinConfig.setMulticastConfig(new MulticastConfig().setEnabled(false));
+ joinConfig.setTcpIpConfig(new TcpIpConfig().
+ setEnabled(true).setMembers(List.of("127.0.0.1")));
+ networkConfig.setJoin(joinConfig);
+
+ cfg.setNetworkConfig(networkConfig);
+ hazelcastInstance = Hazelcast.newHazelcastInstance(cfg);
+
+ HazelcastHelper.otcSystem_setStorageState(true, hazelcastInstance);
+ return new HazelcastService(taskExecutorHazelcastClientInitializer,
+ taskExecutorIdGeneratorAwaiter, params);
+ }
+
+ @Bean(name = "taskExecutorHazelcastClientInitializer")
+ public ThreadPoolTaskExecutor taskExecutorHazelcastClientInitializer() {
+ return createThreadPoolTaskExecutor(1, true);
+ }
+
+ @Bean(name = "taskExecutorIdGeneratorAwaiter")
+ public ThreadPoolTaskExecutor taskExecutorIdGeneratorAwaiter() {
+ return createThreadPoolTaskExecutor(1, false);
+ }
+
+ @Bean(name = "hazelcastClientParams")
+ public HazelcastClientParams getHazelcastClientParams() {
+ HazelcastClientParams params = new HazelcastClientParams();
+ params.setLogin("dev");
+ params.setPassword("dev-pass");
+ params.setClusterMembers("127.0.0.1");
+ params.setInstanceName("hzTestClient" + new Random().nextInt());
+ params.setNearCacheConfig(new NearCacheConfig());
+
+ return params;
+ }
+}
\ No newline at end of file
diff --git a/clearing-parent/utility-service/src/test/java/ru/spcex/clearing/utility/service/KeyRateFactory.java b/clearing-parent/utility-service/src/test/java/ru/spcex/clearing/utility/service/KeyRateFactory.java
new file mode 100644
index 000000000..e5c611ff9
--- /dev/null
+++ b/clearing-parent/utility-service/src/test/java/ru/spcex/clearing/utility/service/KeyRateFactory.java
@@ -0,0 +1,79 @@
+package ru.spcex.clearing.utility.service;
+
+import ru.clearing.classes.statics.data.misc.KeyRate;
+import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
+import ru.spcex.clearing.platform.messaging.domain.cud.utilities.KeyRateNewRequest;
+import ru.spcex.clearing.platform.messaging.domain.cud.utilities.KeyRateUpdateRequest;
+
+import java.time.Instant;
+
+class KeyRateFactory {
+ Instant startDate = Instant.ofEpochSecond(0);
+ Instant endDate = Instant.ofEpochSecond(0);
+ String document = "Test";
+ double rate = 0.5;
+
+ Long id = 0L;
+
+ KeyRateFactory setRate(double rate) {
+ this.rate = rate;
+ return this;
+ }
+
+ KeyRateFactory setEndDate(Instant endDate) {
+ this.endDate = endDate;
+ return this;
+ }
+
+ KeyRateFactory setId(Long id) {
+ this.id = id;
+ return this;
+ }
+
+ KeyRateFactory setDocument(String document) {
+ this.document = document;
+ return this;
+ }
+
+ KeyRateFactory setStartDate(Instant startDate) {
+ this.startDate = startDate;
+ return this;
+ }
+
+ public KeyRate getKeyRate() {
+ KeyRate keyRatePrediction = new KeyRate();
+ keyRatePrediction.setId(id);
+ keyRatePrediction.setDocument(document);
+ keyRatePrediction.setEndDate(endDate.minusSeconds(60 * 60 * 3));
+ keyRatePrediction.setStartDate(startDate.minusSeconds(60 * 60 * 3));
+ keyRatePrediction.setRate(rate);
+ return keyRatePrediction;
+ }
+
+ public KeyRateUpdateRequest getKeyRateUpdateRequest() {
+ KeyRateUpdateRequest keyRateUpdateRequest = new KeyRateUpdateRequest();
+
+ keyRateUpdateRequest.setId(id);
+ keyRateUpdateRequest.setKeyRate(rate);
+ keyRateUpdateRequest.setDocument(document);
+ keyRateUpdateRequest.setStartDate(startDate);
+ keyRateUpdateRequest.setEndDate(endDate);
+
+ return keyRateUpdateRequest;
+ }
+
+ public CommonDeleteRequest getCommonDeleteRequest() {
+ CommonDeleteRequest commonDeleteRequest = new CommonDeleteRequest();
+ commonDeleteRequest.setId(id);
+ return commonDeleteRequest;
+ }
+
+ public KeyRateNewRequest getKeyRateNewRequest() {
+ KeyRateNewRequest keyRequest = new KeyRateNewRequest();
+ keyRequest.setKeyRate(rate);
+ keyRequest.setDocument(document);
+ keyRequest.setEndDate(endDate);
+ keyRequest.setStartDate(startDate);
+ return keyRequest;
+ }
+}
diff --git a/clearing-parent/utility-service/src/test/java/ru/spcex/clearing/utility/service/KeyRateServiceTest.java b/clearing-parent/utility-service/src/test/java/ru/spcex/clearing/utility/service/KeyRateServiceTest.java
new file mode 100644
index 000000000..def1e762a
--- /dev/null
+++ b/clearing-parent/utility-service/src/test/java/ru/spcex/clearing/utility/service/KeyRateServiceTest.java
@@ -0,0 +1,307 @@
+package ru.spcex.clearing.utility.service;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.hazelcast.core.HazelcastInstance;
+import com.hazelcast.core.IMap;
+import com.hazelcast.map.listener.EntryAddedListener;
+import com.hazelcast.map.listener.EntryRemovedListener;
+import com.hazelcast.map.listener.EntryUpdatedListener;
+import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.apache.kafka.clients.consumer.MockConsumer;
+import org.apache.kafka.clients.consumer.OffsetResetStrategy;
+import org.apache.kafka.common.TopicPartition;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import ru.clearing.classes.statics.data.misc.KeyRate;
+import ru.spcex.clearing.imdg.IMDGDistributedNames;
+import ru.spcex.clearing.platform.messaging.domain.ActionType;
+import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
+import ru.spcex.clearing.platform.messaging.domain.Consts;
+import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
+import ru.spcex.clearing.platform.messaging.domain.cud.utilities.KeyRateNewRequest;
+import ru.spcex.clearing.platform.messaging.domain.cud.utilities.KeyRateUpdateRequest;
+import ru.spcex.clearing.utility.config.HazelcastInstanceTestConfiguration;
+import ru.spcex.clearing.utility.config.HazelcastServiceTestConfiguration;
+import ru.spcex.clearing.utility.utils.MatcherFactory;
+import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
+
+import java.time.Instant;
+import java.util.Collections;
+import java.util.HashMap;
+
+@ExtendWith(SpringExtension.class)
+@ContextConfiguration(classes = {
+ HazelcastServiceTestConfiguration.class,
+ HazelcastInstanceTestConfiguration.class})
+public class KeyRateServiceTest {
+ static final ObjectMapper objectMapper = new ObjectMapper();
+ private final int TIMEOUT = 1000;
+ boolean isUsed;
+ private MockConsumer kafkaMockQueue;
+ @Autowired
+ @Qualifier("hazelcastServiceTest")
+ private HazelcastService hazelcastService;
+ @Autowired
+ @Qualifier("hazelcastInstance")
+ private HazelcastInstance hz;
+
+ private void setIsUsed(boolean isUsed) {
+ this.isUsed = isUsed;
+ }
+
+ private String jsonBaseRequest(BaseRequest baseRequest) {
+ String jsonBaseRequest;
+
+ try {
+ jsonBaseRequest = objectMapper.writeValueAsString(baseRequest);
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+
+ return jsonBaseRequest;
+ }
+
+ void initKafka(String topic, int partition, Long offset) {
+ TopicPartition tp = new TopicPartition(topic, partition);
+
+ kafkaMockQueue.schedulePollTask(() -> {
+ kafkaMockQueue.rebalance(Collections.singletonList(tp));
+ });
+
+ HashMap startOffsets = new HashMap<>();
+ startOffsets.put(tp, offset);
+
+ kafkaMockQueue.updateBeginningOffsets(startOffsets);
+ }
+
+ private void startService() throws InterruptedException {
+ KeyRateService keyRateService =
+ new KeyRateService(kafkaMockQueue, hazelcastService);
+ keyRateService.afterPropertiesSet();
+ }
+
+ /**
+ * {@link KeyRateService#newKeyRate(BaseRequest)}
+ * Тест проверяет генерацию сущности {@link KeyRate} в Hazelcast при передаче из Apache Kafka.
+ * Входной запрос {@link KeyRateNewRequest}:
+ * {@link KeyRateNewRequest#keyRate} - 0.5
+ * {@link KeyRateNewRequest#document} - "Test"
+ * {@link KeyRateNewRequest#startDate} - текущее колличество секунд с 1970-01-01T00:00:00Z.
+ * {@link KeyRateNewRequest#endDate} - текущее колличество секунд с 1970-01-01T00:00:00Z.
+ */
+ @Test
+ public void testNewKeyRate() throws InterruptedException {
+ final String TOPIC = Consts.DESTINATION_KEY_RATE_NEW;
+ final String MAP = IMDGDistributedNames.Map_KeyRate;
+
+ final int PARTITION = 0;
+ final Long OFFSET = 0L;
+ final Long REQUEST_ID = 0L;
+
+ final KeyRateFactory keyRateFactory = new KeyRateFactory();
+
+ final KeyRate keyRatePrediction = keyRateFactory.getKeyRate();
+ final KeyRateNewRequest keyRequest = keyRateFactory.getKeyRateNewRequest();
+
+ BaseRequest baseRequest = new BaseRequest();
+
+ baseRequest.setRequestPayload(keyRequest);
+ baseRequest.setId(REQUEST_ID);
+ baseRequest.setActionType(ActionType.NEW);
+
+ String jsonRequest = jsonBaseRequest(baseRequest);
+
+ ConsumerRecord consumerRecord =
+ new ConsumerRecord<>(TOPIC, PARTITION, 0, "key", jsonRequest);
+
+ kafkaMockQueue = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
+ initKafka(TOPIC, PARTITION, OFFSET);
+
+ kafkaMockQueue.schedulePollTask(() -> kafkaMockQueue.addRecord(consumerRecord));
+
+
+ isUsed = false;
+
+ IMap iMap = hz.getMap(MAP);
+
+ Object waiter = new Object();
+
+ String listenerID = iMap.addEntryListener((EntryAddedListener) entryEvent -> {
+ System.out.println("Checking Equality");
+ KeyRate keyRateResult = entryEvent.getValue();
+ keyRatePrediction.setId(entryEvent.getKey());
+
+ MatcherFactory.Matcher matcher = MatcherFactory
+ .usingIgnoringFieldsComparator("id");
+ matcher.assertMatch(keyRateResult, keyRatePrediction);
+ System.out.println("ok");
+ setIsUsed(true);
+ synchronized (waiter) {
+ waiter.notify();
+ }
+ }, true);
+
+ startService();
+
+ synchronized (waiter) {
+ waiter.wait(TIMEOUT);
+ }
+
+ Assertions.assertEquals(true, isUsed);
+ iMap.removeEntryListener(listenerID);
+ }
+
+ /**
+ * {@link KeyRateService#deleteKeyRate(BaseRequest)}
+ * Тест проверяет удаление сущности {@link KeyRate} в Hazelcast при передаче из Apache Kafka.
+ * Входной запрос {@link CommonDeleteRequest}:
+ * {@link CommonDeleteRequest#id} - Идентификатор записи
+ */
+ @Test
+ public void testDeleteKeyRate() throws InterruptedException {
+ final String TOPIC = Consts.DESTINATION_KEY_RATE_DELETE;
+ final String MAP = IMDGDistributedNames.Map_KeyRate;
+
+ final int PARTITION = 0;
+ final Long ID = 1L;
+ final Long OFFSET = 0L;
+ final Long REQUEST_ID = 2L;
+
+ final KeyRateFactory keyRateFactory = new KeyRateFactory()
+ .setId(ID);
+
+ final KeyRate initialKeyRate = keyRateFactory.getKeyRate();
+ final CommonDeleteRequest keyRequest = keyRateFactory.getCommonDeleteRequest();
+
+ BaseRequest baseRequest = new BaseRequest();
+
+ baseRequest.setRequestPayload(keyRequest);
+ baseRequest.setId(REQUEST_ID);
+ baseRequest.setActionType(ActionType.DELETE);
+
+ String jsonRequest = jsonBaseRequest(baseRequest);
+
+ ConsumerRecord consumerRecord =
+ new ConsumerRecord<>(TOPIC, PARTITION, 0, "key", jsonRequest);
+
+ kafkaMockQueue = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
+ initKafka(TOPIC, PARTITION, OFFSET);
+
+ kafkaMockQueue.schedulePollTask(() -> kafkaMockQueue.addRecord(consumerRecord));
+
+
+ isUsed = false;
+
+ IMap iMap = hz.getMap(MAP);
+ iMap.put(ID, initialKeyRate);
+
+ Object waiter = new Object();
+ String listenerID = iMap.addEntryListener((EntryRemovedListener) entryEvent -> {
+ System.out.println("Checking If removed..");
+ Assertions.assertEquals(ID, entryEvent.getKey());
+ System.out.println("ok");
+ setIsUsed(true);
+ synchronized (waiter) {
+ waiter.notify();
+ }
+ }, false);
+
+ startService();
+
+ synchronized (waiter) {
+ waiter.wait(TIMEOUT);
+ }
+
+ Assertions.assertEquals(true, isUsed);
+ iMap.removeEntryListener(listenerID);
+ }
+
+ /**
+ * {@link KeyRateService#updateKeyRate(BaseRequest)}
+ * Тест проверяет генерацию сущности {@link KeyRate} в Hazelcast при передаче из Apache Kafka.
+ * Входной запрос {@link KeyRateUpdateRequest}:
+ * {@link KeyRateUpdateRequest#keyRate} - 5
+ * {@link KeyRateUpdateRequest#document} - "Update"
+ * {@link KeyRateUpdateRequest#startDate} - текущее колличество секунд с 1970-01-01T00:00:00Z + (24 * 3600)
+ * {@link KeyRateUpdateRequest#endDate} - текущее колличество секунд с 1970-01-01T00:00:00Z + (24 * 3600)
+ */
+ @Test
+ public void testUpdateKeyRate() throws InterruptedException {
+ final String TOPIC = Consts.DESTINATION_KEY_RATE_UPDATE;
+ final String MAP = IMDGDistributedNames.Map_KeyRate;
+
+ final int PARTITION = 0;
+ final Long ID = 1L;
+ final Long OFFSET = 0L;
+ final Long REQUEST_ID = 1L;
+
+ final KeyRateFactory keyRateFactory = new KeyRateFactory()
+ .setId(ID);
+
+ final KeyRate initialKeyRate = keyRateFactory.getKeyRate();
+
+ keyRateFactory
+ .setRate(5)
+ .setEndDate(Instant.ofEpochSecond(24 * 3600))
+ .setStartDate(Instant.ofEpochSecond(24 * 3600))
+ .setDocument("Update");
+
+ final KeyRate keyRatePrediction = keyRateFactory.getKeyRate();
+ final KeyRateUpdateRequest keyRequest = keyRateFactory.getKeyRateUpdateRequest();
+
+ BaseRequest baseRequest = new BaseRequest();
+
+ baseRequest.setRequestPayload(keyRequest);
+ baseRequest.setId(REQUEST_ID);
+ baseRequest.setActionType(ActionType.UPDATE);
+
+ String jsonRequest = jsonBaseRequest(baseRequest);
+
+ ConsumerRecord consumerRecord =
+ new ConsumerRecord<>(TOPIC, PARTITION, 0, "key", jsonRequest);
+
+ kafkaMockQueue = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
+ initKafka(TOPIC, PARTITION, OFFSET);
+
+ kafkaMockQueue.schedulePollTask(() -> kafkaMockQueue.addRecord(consumerRecord));
+
+ IMap iMap = hz.getMap(MAP);
+ iMap.put(ID, initialKeyRate);
+
+ isUsed = false;
+
+ Object waiter = new Object();
+ String listenerID = iMap.addEntryListener((EntryUpdatedListener) entryEvent -> {
+ System.out.println("Checking Equality..");
+ KeyRate keyRateResult = entryEvent.getValue();
+
+ MatcherFactory.Matcher matcher = MatcherFactory
+ .usingIgnoringFieldsComparator("id");
+
+ matcher.assertMatch(keyRateResult, keyRatePrediction);
+
+ System.out.println("Ok");
+ setIsUsed(true);
+
+ synchronized (waiter) {
+ waiter.notify();
+ }
+ }, true);
+
+ startService();
+
+ synchronized (waiter) {
+ waiter.wait(TIMEOUT);
+ }
+
+ Assertions.assertEquals(true, isUsed);
+ iMap.removeEntryListener(listenerID);
+ }
+
+}
diff --git a/clearing-parent/utility-service/src/test/java/ru/spcex/clearing/utility/utils/MatcherFactory.java b/clearing-parent/utility-service/src/test/java/ru/spcex/clearing/utility/utils/MatcherFactory.java
new file mode 100644
index 000000000..06162be8f
--- /dev/null
+++ b/clearing-parent/utility-service/src/test/java/ru/spcex/clearing/utility/utils/MatcherFactory.java
@@ -0,0 +1,37 @@
+package ru.spcex.clearing.utility.utils;
+
+import java.util.Arrays;
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Factory for creating test matchers.
+ *
+ * Comparing actual and expected objects via AssertJ
+ */
+public class MatcherFactory {
+
+ public static Matcher usingIgnoringFieldsComparator(String... fieldsToIgnore) {
+ return new Matcher<>(fieldsToIgnore);
+ }
+
+ public static class Matcher {
+ private final String[] fieldsToIgnore;
+
+ private Matcher(String... fieldsToIgnore) {
+ this.fieldsToIgnore = fieldsToIgnore;
+ }
+
+ public void assertMatch(T actual, T expected) {
+ assertThat(actual).usingRecursiveComparison().ignoringFields(fieldsToIgnore).isEqualTo(expected);
+ }
+
+ @SafeVarargs
+ public final void assertMatch(Iterable actual, T... expected) {
+ assertMatch(actual, Arrays.asList(expected));
+ }
+
+ public void assertMatch(Iterable actual, Iterable expected) {
+ assertThat(actual).usingRecursiveFieldByFieldElementComparatorIgnoringFields(fieldsToIgnore).isEqualTo(expected);
+ }
+ }
+}
\ No newline at end of file