Hallo zusammen, meine lieben Freunde, zukünftige Senior Software Engineers. Wir entwickeln weiterhin einen Telegram-Bot. In diesem Schritt unseres Projekts werden wir drei Aufgaben betrachten, die mehr sichtbaren Wert als Programmwert haben. Wir müssen lernen, wie man ein Abonnement für neue Artikel aus einer bestimmten Gruppe entfernt: Verwenden Sie den Befehl /stop , um den Bot zu deaktivieren, und den Befehl /start , um ihn zu aktivieren. Darüber hinaus betreffen alle Anfragen und Aktualisierungen nur aktive Benutzer des Bots. Wie üblich aktualisieren wir den Hauptzweig , um alle Änderungen zu erhalten, und erstellen einen neuen: STEP_7_JRTB-7. In diesem Teil sprechen wir über das Löschen eines Abonnements und betrachten 5 Optionen für Veranstaltungen – das wird interessant sein.
Wir aktualisieren die Version unseres Projekts auf 0.6.0-SNAPSHOT. Wir aktualisieren RELEASE_NOTES.md und fügen eine Beschreibung dessen hinzu, was in der neuen Version getan wurde:
liken – abonnieren – klingeln, unserem Projekt einen Stern geben , Kommentare schreiben und den Artikel bewerten! Danke an alle. Bis zum nächsten Teil. Wir werden bald darüber sprechen, wie man die Bot-Deaktivierung und -Aktivierung über die Befehle /stop und /start hinzufügt und wie man sie am besten nutzt. Bis bald!
JRTB-7: Entfernen eines Abonnements für neue Artikel aus einer Gruppe
Es ist klar, dass alle Benutzer ihr Abonnement löschen möchten, um keine Benachrichtigungen über neue Artikel zu erhalten. Seine Logik wird der Logik des Hinzufügens eines Abonnements sehr ähnlich sein. Wenn wir nur einen Befehl senden, erhalten wir als Antwort eine Liste der Gruppen und deren IDs, bei denen der Benutzer bereits abonniert ist, damit wir verstehen können, was genau gelöscht werden muss. Und wenn der Benutzer die Gruppen-ID zusammen mit dem Team sendet, löschen wir das Abonnement. Lassen Sie uns daher diesen Befehl von der Telegram-Bot-Seite aus entwickeln.-
Fügen wir den Namen des neuen Befehls hinzu – /deleteGroupSub , und in CommandName – die Zeile:
DELETE_GROUP_SUB("/deleteGroupSub")
-
Als nächstes erstellen wir den Befehl „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 = "Пока нет подписок на группы. Wasбы добавить подписку напиши /addGroupSub"; } else { message = "Wasбы удалить подписку на группу - передай комадну вместе с 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;
}
Dadurch verlief alles genau so, wie wir es wollten. Es gibt mehrere mögliche Ereignisse in einem Team, daher ist es eine gute Idee, für jedes davon einen guten Test zu schreiben. Apropos Tests: Während ich sie schrieb, entdeckte ich einen Fehler in der Logik und korrigierte ihn, bevor er in die Produktion ging. Hätte es keinen Test gegeben, ist unklar, wie schnell er entdeckt worden wäre. 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 = "Пока нет подписок на группы. Wasбы добавить подписку напиши /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 = "Wasбы удалить подписку на группу - передай комадну вместе с 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);
}
}
Hier prüft jeder Test ein separates Szenario, und ich möchte Sie daran erinnern, dass es nur fünf davon gibt:
- wenn Sie einfach den Befehl /deleteGroupSub übergeben haben und keine Gruppenabonnements vorhanden sind;
- wenn Sie einfach den Befehl /deleteGroupSub übergeben haben und Abonnements für Gruppen vorhanden sind;
- wenn eine ungültige Gruppen-ID übergeben wurde, zum Beispiel /deleteGroupSub abc ;
- ein Szenario, in dem erwartungsgemäß alles korrekt gelöscht wird;
- Ein Szenario, in dem die Gruppen-ID gültig ist, eine solche Gruppe jedoch nicht in der Datenbank vorhanden ist.
.put(DELETE_GROUP_SUB.getCommandName(),
new DeleteGroupSubCommand(sendBotMessageService, groupSubService, telegramUserService))
Jetzt können Sie die Funktionalität auf einem Testbot testen. Wir starten unsere Datenbank mit docker-compose-test.yml: docker-compose -f docker-compose-test.yml up Und starten SpringBoot über IDEA. Ich werde die Korrespondenz mit dem Bot vollständig löschen und von vorne beginnen. Ich werde alle Optionen durchgehen, die sich bei der Zusammenarbeit mit diesem Team ergeben können. Wie Sie dem Screenshot entnehmen können, wurden alle Optionen durchgegangen und waren erfolgreich.
Freunde! Möchten Sie sofort wissen, wann neuer Code für ein Projekt veröffentlicht wird? Wann erscheint ein neuer Artikel? Treten Sie meinem Telegram-Kanal bei . Dort sammle ich meine Artikel, Gedanken und die Open-Source-Entwicklung zusammen. |
## 0.6.0-SNAPSHOT * JRTB-7: Möglichkeit hinzugefügt, Gruppenabonnements zu löschen.
Der Code funktioniert, es wurden Tests dafür geschrieben: Es ist Zeit, die Aufgabe in das Repository zu verschieben und eine Pull-Anfrage zu erstellen.
GO TO FULL VERSION