Баарыңарга салам, менин кымбаттуу досторум, келечектеги улук программалык камсыздоо инженерлери. Биз телеграмма ботун иштеп чыгууну улантабыз. Долбоорубуздун бул кадамында биз программалык мааниге караганда көрүнүктүү мааниге ээ үч тапшырманы карап чыгабыз. Биз белгилүү бир топтон жаңы макалаларга жазылууну кантип алып салууну үйрөнүшүбүз керек: ботту өчүрүү үчүн /stop командасын колдонуңуз, ал эми аны иштетүү үчүн /start буйругун колдонуңуз. Мындан тышкары, бардык суроо-талаптар жана жаңыртуулар боттун активдүү колдонуучуларына гана тиешелүү. Адаттагыдай эле, бардык өзгөртүүлөрдү алуу жана жаңысын түзүү үчүн негизги бутагын жаңыртабыз : STEP_7_JRTB-7. Бул бөлүктө биз жазылууну жок кылуу жөнүндө сүйлөшөбүз жана окуялардын 5 вариантын карап чыгабыз - бул кызыктуу болот.
Долбоорубуздун versionсын 0.6.0-SNAPSHOT versionсына жаңыртабыз. Биз RELEASE_NOTES.md жаңыртып, жаңы versionда жасалган иштердин сүрөттөмөсүн кошобуз:
лайк басыңыз - жазылыңыз - коңгуроону басыңыз, биздин долбоорго жылдыз бериңиз , комментарий жазыңыз жана макаланы баалаңыз! баарына рахмат. Кийинки бөлүгүнө чейин. /stop & /start буйруктары аркылуу ботту өчүрүү жана активдештирүү жана аларды кантип мыкты колдонуу керектиги жөнүндө жакында сүйлөшөбүз . Көрүшкөнчө!
JRTB-7: топтон жаңы макалаларга жазылууну алып салуу
Бардык колдонуучулар жаңы макалалар жөнүндө эскертмелерди албаш үчүн жазылуусун жок кылууну каалаары анык. Анын логикасы жазылууну кошуу логикасына абдан окшош болот. Эгерде биз бир гана буйрукту жөнөтсөк, жооп катары биз эмнени жок кылуу керектигин түшүнүү үчүн колдонуучу мурунтан эле жазылган топтордун тизмесин жана алардын идентификаторлорун алабыз. Ал эми колдонуучу топ менен бирге ID жөнөтсө, биз жазылууну жок кылабыз. Ошондуктан, келгиле, телеграмма бот тарабынан бул буйрукту иштеп чыгалы.-
Келгиле, жаңы буйруктун атын кошолу - /deleteGroupSub , жана CommandName ичинде - сап:
DELETE_GROUP_SUB("/deleteGroupSub")
-
Андан кийин, келгиле DeleteGroupSubCommand буйругун түзөлү :
package com.github.javarushcommunity.jrtb.command; import com.github.javarushcommunity.jrtb.repository.entity.GroupSub; import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser; import com.github.javarushcommunity.jrtb.service.GroupSubService; import com.github.javarushcommunity.jrtb.service.SendBotMessageService; import com.github.javarushcommunity.jrtb.service.TelegramUserService; import org.springframework.util.CollectionUtils; import org.telegram.telegrambots.meta.api.objects.Update; import javax.ws.rs.NotFoundException; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import static com.github.javarushcommunity.jrtb.command.CommandName.DELETE_GROUP_SUB; import static com.github.javarushcommunity.jrtb.command.CommandUtils.getChatId; import static com.github.javarushcommunity.jrtb.command.CommandUtils.getMessage; import static java.lang.String.format; import static org.apache.commons.lang3.StringUtils.SPACE; import static org.apache.commons.lang3.StringUtils.isNumeric; /** * Delete Group subscription {@link Command}. */ public class DeleteGroupSubCommand implements Command { private final SendBotMessageService sendBotMessageService; private final TelegramUserService telegramUserService; private final GroupSubService groupSubService; public DeleteGroupSubCommand(SendBotMessageService sendBotMessageService, GroupSubService groupSubService, TelegramUserService telegramUserService) { this.sendBotMessageService = sendBotMessageService; this.groupSubService = groupSubService; this.telegramUserService = telegramUserService; } @Override public void execute(Update update) { if (getMessage(update).equalsIgnoreCase(DELETE_GROUP_SUB.getCommandName())) { sendGroupIdList(getChatId(update)); return; } String groupId = getMessage(update).split(SPACE)[1]; String chatId = getChatId(update); if (isNumeric(groupId)) { Optional<GroupSub> optionalGroupSub = groupSubService.findById(Integer.valueOf(groupId)); if (optionalGroupSub.isPresent()) { GroupSub groupSub = optionalGroupSub.get(); TelegramUser telegramUser = telegramUserService.findByChatId(chatId).orElseThrow(NotFoundException::new); groupSub.getUsers().remove(telegramUser); groupSubService.save(groupSub); sendBotMessageService.sendMessage(chatId, format("Удалил подписку на группу: %s", groupSub.getTitle())); } else { sendBotMessageService.sendMessage(chatId, "Не нашел такой группы =/"); } } else { sendBotMessageService.sendMessage(chatId, "неправильный формат ID группы.\n " + "ID должно быть целым положительным числом"); } } private void sendGroupIdList(String chatId) { String message; List<GroupSub> groupSubs = telegramUserService.findByChatId(chatId) .orElseThrow(NotFoundException::new) .getGroupSubs(); if (CollectionUtils.isEmpty(groupSubs)) { message = "Пока нет подписок на группы. Whatбы добавить подписку напиши /addGroupSub"; } else { message = "Whatбы удалить подписку на группу - передай комадну вместе с ID группы. \n" + "Например: /deleteGroupSub 16 \n\n" + "я подготовил список всех групп, на которые ты подписан) \n\n" + "Name группы - ID группы \n\n" + "%s"; } String userGroupSubData = groupSubs.stream() .map(group -> format("%s - %s \n", group.getTitle(), group.getId())) .collect(Collectors.joining()); sendBotMessageService.sendMessage(chatId, format(message, userGroupSubData)); } }
@Data
@Entity
@Table(name = "tg_user")
@EqualsAndHashCode(exclude = "groupSubs")
public class TelegramUser {
@Id
@Column(name = "chat_id")
private String chatId;
@Column(name = "active")
private boolean active;
@ManyToMany(mappedBy = "users", fetch = FetchType.EAGER)
private List<GroupSub> groupSubs;
}
Натыйжада баары биз каалагандай болуп кетти. Командада бир нече мүмкүн болгон окуялар бар, андыктан алардын ар бири үчүн жакшы тест жазуу сонун идея. Тесттер жөнүндө айтсам: мен аларды жазып жатып, логикада кемчorк таап, аны өндүрүшкө чыгара электе оңдоп койдум. Эгерде эч кандай сыноо болбогондо, ал канчалык тез аныкталмак экени белгисиз. DeleteGroupSubCommandTest:
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import com.github.javarushcommunity.jrtb.service.GroupSubService;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.telegram.telegrambots.meta.api.objects.Update;
import java.util.ArrayList;
import java.util.Optional;
import static com.github.javarushcommunity.jrtb.command.AbstractCommandTest.prepareUpdate;
import static com.github.javarushcommunity.jrtb.command.CommandName.DELETE_GROUP_SUB;
import static java.util.Collections.singletonList;
@DisplayName("Unit-level testing for DeleteGroupSubCommand")
class DeleteGroupSubCommandTest {
private Command command;
private SendBotMessageService sendBotMessageService;
GroupSubService groupSubService;
TelegramUserService telegramUserService;
@BeforeEach
public void init() {
sendBotMessageService = Mockito.mock(SendBotMessageService.class);
groupSubService = Mockito.mock(GroupSubService.class);
telegramUserService = Mockito.mock(TelegramUserService.class);
command = new DeleteGroupSubCommand(sendBotMessageService, groupSubService, telegramUserService);
}
@Test
public void shouldProperlyReturnEmptySubscriptionList() {
//given
Long chatId = 23456L;
Update update = prepareUpdate(chatId, DELETE_GROUP_SUB.getCommandName());
Mockito.when(telegramUserService.findByChatId(String.valueOf(chatId)))
.thenReturn(Optional.of(new TelegramUser()));
String expectedMessage = "Пока нет подписок на группы. Whatбы добавить подписку напиши /addGroupSub";
//when
command.execute(update);
//then
Mockito.verify(sendBotMessageService).sendMessage(chatId.toString(), expectedMessage);
}
@Test
public void shouldProperlyReturnSubscriptionLit() {
//given
Long chatId = 23456L;
Update update = prepareUpdate(chatId, DELETE_GROUP_SUB.getCommandName());
TelegramUser telegramUser = new TelegramUser();
GroupSub gs1 = new GroupSub();
gs1.setId(123);
gs1.setTitle("GS1 Title");
telegramUser.setGroupSubs(singletonList(gs1));
Mockito.when(telegramUserService.findByChatId(String.valueOf(chatId)))
.thenReturn(Optional.of(telegramUser));
String expectedMessage = "Whatбы удалить подписку на группу - передай комадну вместе с ID группы. \n" +
"Например: /deleteGroupSub 16 \n\n" +
"я подготовил список всех групп, на которые ты подписан) \n\n" +
"Name группы - ID группы \n\n" +
"GS1 Title - 123 \n";
//when
command.execute(update);
//then
Mockito.verify(sendBotMessageService).sendMessage(chatId.toString(), expectedMessage);
}
@Test
public void shouldRejectByInvalidGroupId() {
//given
Long chatId = 23456L;
Update update = prepareUpdate(chatId, String.format("%s %s", DELETE_GROUP_SUB.getCommandName(), "groupSubId"));
TelegramUser telegramUser = new TelegramUser();
GroupSub gs1 = new GroupSub();
gs1.setId(123);
gs1.setTitle("GS1 Title");
telegramUser.setGroupSubs(singletonList(gs1));
Mockito.when(telegramUserService.findByChatId(String.valueOf(chatId)))
.thenReturn(Optional.of(telegramUser));
String expectedMessage = "неправильный формат ID группы.\n " +
"ID должно быть целым положительным числом";
//when
command.execute(update);
//then
Mockito.verify(sendBotMessageService).sendMessage(chatId.toString(), expectedMessage);
}
@Test
public void shouldProperlyDeleteByGroupId() {
//given
/// prepare update object
Long chatId = 23456L;
Integer groupId = 1234;
Update update = prepareUpdate(chatId, String.format("%s %s", DELETE_GROUP_SUB.getCommandName(), groupId));
GroupSub gs1 = new GroupSub();
gs1.setId(123);
gs1.setTitle("GS1 Title");
TelegramUser telegramUser = new TelegramUser();
telegramUser.setChatId(chatId.toString());
telegramUser.setGroupSubs(singletonList(gs1));
ArrayList<TelegramUser> users = new ArrayList<>();
users.add(telegramUser);
gs1.setUsers(users);
Mockito.when(groupSubService.findById(groupId)).thenReturn(Optional.of(gs1));
Mockito.when(telegramUserService.findByChatId(String.valueOf(chatId)))
.thenReturn(Optional.of(telegramUser));
String expectedMessage = "Удалил подписку на группу: GS1 Title";
//when
command.execute(update);
//then
users.remove(telegramUser);
Mockito.verify(groupSubService).save(gs1);
Mockito.verify(sendBotMessageService).sendMessage(chatId.toString(), expectedMessage);
}
@Test
public void shouldDoesNotExistByGroupId() {
//given
Long chatId = 23456L;
Integer groupId = 1234;
Update update = prepareUpdate(chatId, String.format("%s %s", DELETE_GROUP_SUB.getCommandName(), groupId));
Mockito.when(groupSubService.findById(groupId)).thenReturn(Optional.empty());
String expectedMessage = "Не нашел такой группы =/";
//when
command.execute(update);
//then
Mockito.verify(groupSubService).findById(groupId);
Mockito.verify(sendBotMessageService).sendMessage(chatId.toString(), expectedMessage);
}
}
Бул жерде ар бир тест өзүнчө сценарийди текшерет жана мен сизге эскертип коёюн, алардын бешөө гана бар:
- сиз жөн гана /deleteGroupSub буйругун тапшырганыңызда жана топко жазылуулар жок болгондо;
- сиз жөн гана /deleteGroupSub буйругун тапшырганыңызда жана топторго жазылуулар болгондо;
- жараксыз топ ID өткөндө, мисалы, /deleteGroupSub abc ;
- күтүлгөндөй баары туура жок кылынган сценарий;
- топтун ID жарактуу болгон сценарий, бирок мындай топ маалымат базасында жок.
.put(DELETE_GROUP_SUB.getCommandName(),
new DeleteGroupSubCommand(sendBotMessageService, groupSubService, telegramUserService))
Эми сиз функцияны сыноо ботунда текшере аласыз. Биз базабызды docker-compose-test.yml аркылуу ишке киргизебиз: docker-compose -f docker-compose-test.yml up Жана IDEA аркылуу SpringBootту ишке киргизебиз. Мен бот менен кат алышууну толугу менен тазалап, кайра баштайм. Мен бул команда менен иштөөдө пайда болушу мүмкүн болгон бардык варианттарды карап чыгам. Скриншоттон көрүнүп тургандай, бардык варианттар өтүп, ийгorктүү болду.
Достор! Долбоордун жаңы codeу качан чыгарылганын дароо билгиңиз келеби? Жаңы макала качан чыгат? Менин Telegram каналыма кошулуңуз . Ал жерде мен өзүмдүн макалаларымды, ойлорумду жана ачык булактарды иштеп чыгууларды чогуу чогултам. |
## 0.6.0-SNAPSHOT * JRTB-7: топко жазылууну жок кылуу мүмкүнчүлүгү кошулду.
Код иштейт, ал үчүн тесттер жазылган: тапшырманы репозиторийге түртүп, тартуу өтүнүчүн түзүүгө убакыт келди.
GO TO FULL VERSION