Здравствуйте, Dziman, Вы писали:
D> У меня тут случился затуп и/или недопонимание: D> Тестовая задача получить по rest информацию, отправить ее в message queue, получить оттуда и прочитав файл вернуть допинформацию если она есть. Код вышел таким: D> https://bitbucket.org/Dziman/tt/src/2a84a61783ffa8907a0862b84c6822c3bd809b8e/?at=client_info D> Что тут можно и имеет смысл тестировать юнит тестами?
ClientInfoManagementController покрывается хорошо. Можно покрыть что возвращаемый статус NOT_FOUND или OK в зависимости от поведения замоканного cardDetailsService.
CardDetailsServiceCSVImpl покрывается тоже. Например, такой тест: делаем "createClientInfo" и убеждаемся что getClientInfo возвращает то что надо. Скажем, этот тест проверит, что ты не перепутаешь колонки name и surname во время записи и чтения.
Ну и тесты поиска, возвращения списка, и т.п.
ClientInfoService покрывается тоже. Например, убедиться что correlationId не потерялся, что setSuccess проставляется правильно false/true, setCardNumber правильный и т.п.
ClientInfoServiceJMSImpl тоже можно покрыть, что, например, выбор correlationId происходит такой же. Ну и даже можно запилить тест, котоый проверит, что два запроса используют разные correlationId.
А однострочные методы с одним вариантом исполнения... да... можно и не тестировать.
Здравствуйте, ·, Вы писали:
·> D> У меня тут случился затуп и/или недопонимание: ·> D> Тестовая задача получить по rest информацию, отправить ее в message queue, получить оттуда и прочитав файл вернуть допинформацию если она есть. Код вышел таким: ·> D> https://bitbucket.org/Dziman/tt/src/2a84a61783ffa8907a0862b84c6822c3bd809b8e/?at=client_info ·> D> Что тут можно и имеет смысл тестировать юнит тестами?
·> ClientInfoManagementController покрывается хорошо. Можно покрыть что возвращаемый статус NOT_FOUND или OK в зависимости от поведения замоканного cardDetailsService.
Мне кажется что если мы мокаем cardDetailsService, то весь этот тест суть то же что и тестирование простых аксессоров.
·> CardDetailsServiceCSVImpl покрывается тоже. Например, такой тест: делаем "createClientInfo" и убеждаемся что getClientInfo возвращает то что надо. Скажем, этот тест проверит, что ты не перепутаешь колонки name и surname во время записи и чтения. ·> Ну и тесты поиска, возвращения списка, и т.п. ·> ClientInfoService покрывается тоже. Например, убедиться что correlationId не потерялся, что setSuccess проставляется правильно false/true, setCardNumber правильный и т.п. ·> ClientInfoServiceJMSImpl тоже можно покрыть, что, например, выбор correlationId происходит такой же. Ну и даже можно запилить тест, котоый проверит, что два запроса используют разные correlationId. ·> А однострочные методы с одним вариантом исполнения... да... можно и не тестировать.
ОК, описанные тесты вполне логичны и проверяют что-то значимое. Но в моем понимании это ни разу не юнит тесты, а интеграционные.
Здравствуйте, Dziman, Вы писали:
D> Мне кажется что если мы мокаем cardDetailsService, то весь этот тест суть то же что и тестирование простых аксессоров.
Нет. Тестируется, что ты, например, не падаешь по NPE если элемент не найден, а возвращаешь ожидаемый 404.
D> ОК, описанные тесты вполне логичны и проверяют что-то значимое. Но в моем понимании это ни разу не юнит тесты, а интеграционные.
Интеграционными они будут если у тебя будет несколько классов собирается. Ты же мокаешь все зависимости. Т.е. не надо запускать JMS-брокер и т.п., а просто заинжектить моки.
Хотя, в принципе да, тест для CardDetailsServiceCSVImpl можно назвать интеграционным, ибо там файл в файловой системе будет использоваться...
Здравствуйте, ·, Вы писали:
·> D> Мне кажется что если мы мокаем cardDetailsService, то весь этот тест суть то же что и тестирование простых аксессоров.
·> Нет. Тестируется, что ты, например, не падаешь по NPE если элемент не найден, а возвращаешь ожидаемый 404.
·> D> ОК, описанные тесты вполне логичны и проверяют что-то значимое. Но в моем понимании это ни разу не юнит тесты, а интеграционные.
·> Интеграционными они будут если у тебя будет несколько классов собирается. Ты же мокаешь все зависимости. Т.е. не надо запускать JMS-брокер и т.п., а просто заинжектить моки. ·> Хотя, в принципе да, тест для CardDetailsServiceCSVImpl можно назвать интеграционным, ибо там файл в файловой системе будет использоваться...
Так дело в том что если замокать все внешнее тип JMS–брокера, storage (работа с csv), то тесты получаются
Response r = new Response();
when(mock.method()).thenReturn(r);
assertEquals(r, testObj.call()); // call() { return mock.method();}
Здравствуйте, Dziman, Вы писали:
D> Так дело в том что если замокать все внешнее тип JMS–брокера, storage (работа с csv), то тесты получаются D>
D> Response r = new Response();
D> when(mock.method()).thenReturn(r);
D> assertEquals(r, testObj.call()); // call() { return mock.method();}
D>
D> и смысла в нем чут менее чем нет.
Ну почему же. Вот рассмотрим ClientInfoService. Там пара десятков значимых строк кода, налажать есть где, совсем не "call() { return mock.method();}"
Надо замокать jmsTemplate и проверить, что вызывается setJMSCorrelationID с правильным id, нужно проверить что ненайденный cardNumber не вызывает NPE, а правильно проставляет setSuccess.
Ещё конструируется сложный InfoResponse объект: надо проверить, что никакие сеттеры не забыты.
Здравствуйте, ·, Вы писали:
·> Ну почему же. Вот рассмотрим ClientInfoService. Там пара десятков значимых строк кода, налажать есть где, совсем не "call() { return mock.method();}" ·> Надо замокать jmsTemplate и проверить, что вызывается setJMSCorrelationID с правильным id, нужно проверить что ненайденный cardNumber не вызывает NPE, а правильно проставляет setSuccess. ·> Ещё конструируется сложный InfoResponse объект: надо проверить, что никакие сеттеры не забыты.
Попробуем рассмотреть. Итак, имеем класс
package com.meawallet.secured.service;
@Service
public class ClientInfoService implements MessageListener {
@Autowired
private JmsTemplate jmsTemplate;
@Autowired
private Queue clientInfoResponseQueue;
@Autowired
private CardDetailsService cardDetailsService;
@Override
public void onMessage(Message message) {
if (message instanceof ObjectMessage) {
try {
InfoRequest infoRequest = (InfoRequest) ((ObjectMessage) message).getObject();
final String correlationId = message.getJMSCorrelationID();
final InfoResponse infoResponse = process(infoRequest);
jmsTemplate.send(clientInfoResponseQueue, session -> {
ObjectMessage objectMessage = session.createObjectMessage(infoResponse);
objectMessage.setJMSCorrelationID(correlationId);
return objectMessage;
});
} catch (JMSException ex) {
throw new RuntimeException(ex);
}
} else {
throw new IllegalArgumentException("Message must be of type ObjectMessage");
}
}
InfoResponse process(InfoRequest infoRequest) {
InfoResponse result = new InfoResponse();
Info resultInfo = new Info();
List<CardDetails> resultCardDetails = infoRequest.getInfo().getCardDetails().stream()
.map(cardDetails -> {
Optional<CardDetails> optionalClientInfo = cardDetailsService.getClientInfo(cardDetails.getCardNumber());
return optionalClientInfo.orElseGet(() -> {
CardDetails clientInfo = new CardDetails();
clientInfo.setSuccess(false);
clientInfo.setCardNumber(cardDetails.getCardNumber());
return clientInfo;
});
})
.collect(Collectors.toList());
resultInfo.setCardDetails(resultCardDetails);
result.setInfo(resultInfo);
return result;
}
}
onMessage в целом юнит тестом мы проверить не можем никак, т.к. там идет работа с JMS. Т.е. этот метод остается для интеграционных тестов.
process уже имеет некоторую логику и его вполне можно поюниттестировать
Здравствуйте, Dziman, Вы писали:
D> ·> Ну почему же. Вот рассмотрим ClientInfoService. Там пара десятков значимых строк кода, налажать есть где, совсем не "call() { return mock.method();}" D> ·> Надо замокать jmsTemplate и проверить, что вызывается setJMSCorrelationID с правильным id, нужно проверить что ненайденный cardNumber не вызывает NPE, а правильно проставляет setSuccess. D> ·> Ещё конструируется сложный InfoResponse объект: надо проверить, что никакие сеттеры не забыты.
D> Попробуем рассмотреть. Итак, имеем класс
D>
D> onMessage в целом юнит тестом мы проверить не можем никак, т.к. там идет работа с JMS. Т.е. этот метод остается для интеграционных тестов. D> process уже имеет некоторую логику и его вполне можно поюниттестировать
D> Всё. У меня больше нет никаких идей и фантазии что можно тестировать юнит тестами в этом приложении
Да какие-то странные тесты вообще. Создаёшь кучу prepareCardDetails, но не используешь. SuppressWarnings накой?!
Юнит-тесты — это whitebox-тесты. Т.е. ты должен смотреть на реализацию и писать.
Кстати, JmsTemplate это реализация, а зависеть надо от интерфейса, JmsOperations.
Потом бы выносил общий код из тестов в приватные методы, простенькие mock-классы, например Session явно будет переиспользоваться из многих мест, поди и готовый класс уже есть в Спринге?..