שלום לכולם, חברים יקרים שלי, מהנדסי תוכנה בכירים לעתיד. אנו ממשיכים לפתח בוט טלגרם. בשלב זה של הפרויקט שלנו, נשקול שלוש משימות בעלות ערך גלוי יותר מערך התוכנית. עלינו ללמוד כיצד להסיר מנוי למאמרים חדשים מקבוצה מסוימת: השתמש בפקודה /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 למעלה ומשיקים את SpringBoot דרך IDEA. אני אנקה לחלוטין את ההתכתבות עם הבוט ואתחיל מחדש. אני אעבור על כל האפשרויות שעלולות לצוץ בעבודה עם הצוות הזה. כפי שניתן לראות מצילום המסך, כל האפשרויות עברו והצליחו.
חברים! האם אתה רוצה לדעת מיד מתי יוצא קוד חדש לפרויקט? מתי יוצא כתבה חדשה? הצטרף לערוץ הטלגרם שלי . שם אני אוסף את המאמרים, המחשבות ופיתוח הקוד הפתוח שלי ביחד. |
## 0.6.0-SNAPSHOT * JRTB-7: הוספה את היכולת למחוק מנוי קבוצתי.
הקוד עובד, נכתבו עבורו בדיקות: הגיע הזמן לדחוף את המשימה למאגר וליצור בקשת משיכה.
GO TO FULL VERSION