Баршаңызға сәлем, қымбатты достарым, болашақ аға бағдарламалық жасақтама инженерлері. Біз телеграмма ботын дамытуды жалғастырамыз. Жобамыздың бұл қадамында біз бағдарлама мәнінен гөрі көрінетін мәнге ие үш тапсырманы қарастырамыз. Белгілі бір топтан жаңа мақалаларға жазылуды қалай жою керектігін үйренуіміз керек: ботты өшіру үшін /stop пәрменін пайдаланыңыз және оны белсендіру үшін /start пәрменін пайдаланыңыз. Сонымен қатар, барлық сұраулар мен жаңартулар тек белсенді бот пайдаланушыларына қатысты. Әдеттегідей, барлық өзгерістерді алу және жаңасын жасау үшін негізгі тармақты жаңартамыз : STEP_7_JRTB-7. Бұл бөлімде біз жазылымды жою туралы сөйлесеміз және оқиғалардың 5 нұсқасын қарастырамыз - бұл қызықты болады.
Біз жобамыздың нұсқасын 0.6.0-SNAPSHOT нұсқасына жаңартамыз, RELEASE_NOTES.md жаңа нұсқасында жасалған әрекеттердің сипаттамасын қоса отырып, жаңартамыз:
лайк басыңыз - жазылыңыз - қоңырауды басыңыз, жобамызға жұлдызша беріңіз , пікір қалдырыңыз және мақаланы бағалаңыз! Барлығыңа Рақмет. Келесі бөлімге дейін. Жақында біз /stop & /start пәрмендері арқылы ботты өшіруді және белсендіруді қосу және оларды қалай жақсы пайдалану керектігі туралы сөйлесетін боламыз. Көріскенше!
JRTB-7: топтан жаңа мақалаларға жазылуды жою
Жаңа мақалалар туралы хабарландыруларды алмау үшін барлық пайдаланушылар жазылымын жойғысы келетіні анық. Оның логикасы жазылымды қосу логикасына өте ұқсас болады. Егер біз тек бір пәрменді жіберсек, жауап ретінде біз нені жою керектігін түсіну үшін пайдаланушы бұрыннан жазылған топтардың тізімін және олардың идентификаторларын аламыз. Ал егер пайдаланушы топтың идентификаторын командамен бірге жіберсе, біз жазылымды жоямыз. Сондықтан, осы пәрменді телеграмма бот жағынан әзірлейік.-
Жаңа пәрменнің атын қосамыз - /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;
}
Нәтижесінде бәрі біз қалағандай болды. Командада бірнеше ықтимал оқиғалар болуы мүмкін, сондықтан олардың әрқайсысы үшін жақсы сынақ жазу тамаша идея. Тесттер туралы айтатын болсақ: мен оларды жазып жатқанда, мен логикадан ақау тауып, оны өндіріске жібермес бұрын түзетіп алдым. Егер сынақ болмаса, оның қаншалықты тез анықталатыны белгісіз. 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 пәрменін жай ғана тапсырған кезде және топтарға жазылулар болған кезде;
- жарамсыз топ идентификаторы жіберілгенде, мысалы, /deleteGroupSub abc ;
- күткендей бәрі дұрыс жойылатын сценарий;
- топ идентификаторы жарамды, бірақ мұндай топ дерекқорда болмаған кездегі сценарий.
.put(DELETE_GROUP_SUB.getCommandName(),
new DeleteGroupSubCommand(sendBotMessageService, groupSubService, telegramUserService))
Енді сіз функционалдылықты сынақ ботында тексере аласыз. Біз дерекқорымызды docker-compose-test.yml арқылы іске қосамыз: docker-compose -f docker-compose-test.yml up және SpringBoot бағдарламасын IDEA арқылы іске қосамыз. Мен ботпен хат алмасуды толығымен тазалап, қайтадан бастаймын. Мен осы топпен жұмыс істеу кезінде туындауы мүмкін барлық нұсқаларды қарастырамын. Скриншоттан көріп отырғаныңыздай, барлық опциялар сәтті өтті.
Достар! Жобаның жаңа codeы қашан шыққанын бірден білгіңіз келе ме? Жаңа мақала қашан шығады? Менің Telegram каналыма қосылыңыз . Онда мен мақалаларымды, ойларымды және ашық дереккөзді әзірлеуді бірге жинаймын. |
## 0.6.0-SNAPSHOT * JRTB-7: топтық жазылымды жою мүмкіндігі қосылды.
Код жұмыс істейді, ол үшін сынақтар жазылды: тапсырманы репозиторийге енгізу және тарту сұрауын жасау уақыты келді.
GO TO FULL VERSION