สวัสดีทุกคน เพื่อนรัก วิศวกรซอฟต์แวร์อาวุโสในอนาคต เรายังคงพัฒนาบอทโทรเลขต่อไป ในขั้นตอนนี้ของโครงการ เราจะพิจารณางานสามงานที่มีคุณค่าที่มองเห็นได้มากกว่ามูลค่าโปรแกรม เราจำเป็นต้องเรียนรู้วิธีลบการสมัครรับบทความใหม่จากกลุ่มเฉพาะ: ใช้ คำสั่ง /stopเพื่อปิดการใช้งานบอท และใช้ คำสั่ง /startเพื่อเปิดใช้งาน นอกจากนี้ คำขอและการอัปเดตทั้งหมดเกี่ยวข้องกับผู้ใช้บอทที่ใช้งานอยู่เท่านั้น ตามปกติ เราจะอัปเดต สาขา หลักเพื่อรับการเปลี่ยนแปลงทั้งหมดและสร้างสาขาใหม่: STEP_7_JRTB-7 ในส่วนนี้เราจะพูดถึงการลบการสมัครสมาชิกและพิจารณา 5 ตัวเลือกสำหรับกิจกรรม - มันจะน่าสนใจ
!["โครงการ Java จาก A ถึง Z": การลบการสมัครสมาชิกบทความออกจากกลุ่ม - 1]()
หากต้องการลบผู้ใช้ออกอย่างรวดเร็ว ฉันได้เพิ่มคำอธิบายประกอบ EqualsAndHashCode ให้กับ TelegramUser โดยไม่รวมรายการ GroupSub เพื่อไม่ให้เกิดปัญหา และเรียกวิธีการลบในการรวบรวมผู้ใช้กับผู้ใช้ที่เราต้องการ นี่คือลักษณะของ TelegramUser:
แน่นอนว่าเพื่อให้คำสั่งนี้ใช้งานได้ คุณต้องเพิ่มการกำหนดค่าเริ่มต้นให้กับCommandContainer :
อย่างที่คุณเห็นจากภาพหน้าจอ ตัวเลือกทั้งหมดผ่านไปและประสบความสำเร็จ
เราอัปเดตเวอร์ชันของโครงการของเราเป็น 0.6.0-SNAPSHOT เราอัปเดต RELEASE_NOTES.md โดยเพิ่มคำอธิบายของสิ่งที่ได้ทำไปแล้วในเวอร์ชันใหม่:
เหลือเพียง 5 งานเท่านั้น นั่นคือคุณและฉันอยู่สุดถนนแล้ว เหลือนิดหน่อย. เป็นเรื่องที่น่าสนใจอย่างยิ่งที่ทราบว่าบทความชุดนี้เผยแพร่ตั้งแต่กลางเดือนกันยายนนั่นคือเป็นเวลา 7 เดือน!!! เมื่อฉันคิดไอเดียนี้ขึ้นมา ฉันไม่ได้คาดหวังว่ามันจะใช้เวลานานนัก ในขณะเดียวกัน ฉันก็พอใจกับผลลัพธ์ที่ได้มาก! เพื่อน ๆ หากยังไม่ชัดเจนว่าเกิดอะไรขึ้นในบทความให้ถามคำถามในความคิดเห็น ด้วยวิธีนี้ฉันจะรู้ว่าบางสิ่งจำเป็นต้องอธิบายให้ดีขึ้น และบางสิ่งจำเป็นต้องอธิบายเพิ่มเติม ตามปกติเช่น - สมัครสมาชิก - กดกริ่งให้ ดาว โครงการของเราเขียนความคิดเห็นและให้คะแนนบทความ! ขอบคุณทุกคน. จนกระทั่งถึงภาคต่อไป เราจะพูดถึงวิธีเพิ่มการปิดใช้งานและการเปิดใช้งานบอทผ่าน คำสั่ง /stop & /startและวิธีใช้งานให้ดีที่สุด เร็วๆ นี้ แล้วพบกันใหม่!
JRTB-7: ลบการสมัครสมาชิกบทความใหม่ออกจากกลุ่ม
เป็นที่ชัดเจนว่าผู้ใช้ทุกคนจะต้องการลบการสมัครสมาชิกของตนเพื่อไม่ให้ได้รับการแจ้งเตือนเกี่ยวกับบทความใหม่ ตรรกะของมันจะคล้ายกับตรรกะของการเพิ่มการสมัครสมาชิกมาก หากเราส่งเพียงคำสั่งเดียว เพื่อเป็นการตอบสนองเราจะได้รับรายชื่อกลุ่มและ ID ของกลุ่มที่ผู้ใช้ได้สมัครรับข้อมูลไว้แล้ว เพื่อที่เราจะได้เข้าใจได้ว่าจำเป็นต้องลบสิ่งใดอย่างแน่นอน และหากผู้ใช้ส่ง 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;
}
เป็นผลให้ทุกอย่างดำเนินไปอย่างที่เราต้องการ มีเหตุการณ์ที่เป็นไปได้หลายอย่างในทีม ดังนั้น การเขียนแบบทดสอบที่ดีสำหรับแต่ละเหตุการณ์จึงเป็นความคิดที่ดี เมื่อพูดถึงการทดสอบ: ขณะที่ฉันกำลังเขียน ฉันพบข้อบกพร่องในตรรกะและแก้ไขก่อนที่จะเผยแพร่สู่การใช้งานจริง หากไม่มีการทดสอบ ก็ไม่มีความชัดเจนว่าจะตรวจพบได้เร็วแค่ไหน ลบ GroupSubCommandTest:
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 และเปิด SpringBoot ผ่าน IDEA ฉันจะล้างการติดต่อกับบอทให้หมดและเริ่มต้นใหม่อีกครั้ง ฉันจะพิจารณาตัวเลือกทั้งหมดที่อาจเกิดขึ้นเมื่อทำงานร่วมกับทีมนี้ 
เพื่อน! คุณต้องการทราบทันทีเมื่อมีการออกโค้ดใหม่สำหรับโปรเจ็กต์หรือไม่? เมื่อไหร่จะมีบทความใหม่ออกมา? เข้าร่วมช่องโทรเลข ของ ฉัน ที่นั่นฉันรวบรวมบทความ ความคิด และการพัฒนาโอเพ่นซอร์สของฉันไว้ด้วยกัน |
## 0.6.0-SNAPSHOT * JRTB-7: เพิ่มความสามารถในการลบการสมัครสมาชิกกลุ่ม
รหัสใช้งานได้ มีการเขียนการทดสอบแล้ว: ถึงเวลาที่จะผลักดันงานเข้าไปในพื้นที่เก็บข้อมูลและสร้างคำขอดึง
แทนที่จะจบ.
เราไม่ได้ดูบอร์ดโครงการของเรามานานแล้ว แต่มีการเปลี่ยนแปลงครั้งใหญ่:
GO TO FULL VERSION