Biz dastur uchun testlar yozamiz
Maqolaning boshlanishi:
JRTB-3 yozish . Endi biz sinov haqida o'ylashimiz kerak. Funktsionallik biz kutgandek ishlashiga ishonch hosil qilishimiz uchun barcha qo'shilgan kodlar testlar bilan qoplanishi kerak. Avval biz SendBotMessageService xizmati uchun birlik testlarini yozamiz.
Birlik testi - bu dasturning kichik bir qismining mantiqini sinab ko'radigan test: odatda bu usullar. Va bu usulga ega bo'lgan barcha ulanishlar masxara yordamida soxta narsalar bilan almashtiriladi. |
Endi siz hamma narsani ko'rasiz. Xuddi shu paketda, faqat
./src/test/java papkasida biz sinab ko'radigan sinf bilan bir xil nomdagi sinf yaratamiz va oxirida
Test ni qo'shamiz . Ya'ni,
SendBotMessageService uchun bizda SendBotMessageServiceTest bo'ladi , bu sinf uchun barcha testlarni o'z ichiga oladi. Uni sinovdan o'tkazish g'oyasi quyidagicha: biz soxta (soxta) JavaRushTelegarmBot-ga o'tamiz, undan so'ng biz bajarish usuli shunday dalil bilan chaqirilganmi yoki yo'qmi, deb so'raymiz. Mana nima bo'ldi:
package com.github.javarushcommunity.jrtb.service;
import com.github.javarushcommunity.jrtb.bot.JavarushTelegramBot;
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.methods.send.SendMessage;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
@DisplayName("Unit-level testing for SendBotMessageService")
public class SendBotMessageServiceTest {
private SendBotMessageService sendBotMessageService;
private JavarushTelegramBot javarushBot;
@BeforeEach
public void init() {
javarushBot = Mockito.mock(JavarushTelegramBot.class);
sendBotMessageService = new SendBotMessageServiceImpl(javarushBot);
}
@Test
public void shouldProperlySendMessage() throws TelegramApiException {
String chatId = "test_chat_id";
String message = "test_message";
SendMessage sendMessage = new SendMessage();
sendMessage.setText(message);
sendMessage.setChatId(chatId);
sendMessage.enableHtml(true);
sendBotMessageService.sendMessage(chatId, message);
Mockito.verify(javarushBot).execute(sendMessage);
}
}
Mockito-dan foydalanib, men soxta JavaRushBot ob'ektini yaratdim va uni xizmatimiz konstruktoriga topshirdim. Keyin men bitta test yozdim (Test izohi bilan har bir usul alohida test). Ushbu usulning tuzilishi har doim bir xil - u hech qanday dalil talab qilmaydi va bekor qiladi. Sinov nomi biz nimani sinab ko'rayotganimizni ko'rsatishi kerak. Bizning holatda, bu: xabarni to'g'ri yuborish kerak - xabarni to'g'ri yuborish kerak. Bizning testimiz uch qismga bo'lingan:
- blok //berilgan - bu erda biz test uchun zarur bo'lgan hamma narsani tayyorlaymiz;
- blok //qachon - biz sinab ko'rishni rejalashtirgan usulni ishga tushiradigan joy;
- //keyin blok - bu erda usul to'g'ri ishlaganligini tekshiramiz.
Bizning xizmatimizdagi mantiq hozircha oddiy bo'lgani uchun, bu sinf uchun bitta test etarli bo'ladi. Endi CommandContainer uchun test yozamiz:
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import java.util.Arrays;
@DisplayName("Unit-level testing for CommandContainer")
class CommandContainerTest {
private CommandContainer commandContainer;
@BeforeEach
public void init() {
SendBotMessageService sendBotMessageService = Mockito.mock(SendBotMessageService.class);
commandContainer = new CommandContainer(sendBotMessageService);
}
@Test
public void shouldGetAllTheExistingCommands() {
Arrays.stream(CommandName.values())
.forEach(commandName -> {
Command command = commandContainer.retrieveCommand(commandName.getCommandName());
Assertions.assertNotEquals(UnknownCommand.class, command.getClass());
});
}
@Test
public void shouldReturnUnknownCommand() {
String unknownCommand = "/fgjhdfgdfg";
Command command = commandContainer.retrieveCommand(unknownCommand);
Assertions.assertEquals(UnknownCommand.class, command.getClass());
}
}
Bu juda aniq sinov emas. Bu konteynerning mantig'iga tayanadi. Bot qo'llab-quvvatlaydigan barcha buyruqlar Buyruqning nomi ro'yxatida va konteynerda bo'lishi kerak. Shunday qilib, men barcha CommandName o'zgaruvchilarini oldim, Stream API-ga o'tdim va har biri uchun konteynerdan buyruq qidirdim. Agar bunday buyruq bo'lmasa, Noma'lum buyruq qaytariladi. Biz ushbu qatorda tekshiramiz:
Assertions.assertNotEquals(UnknownCommand.class, command.getClass());
UnknownCommand standart bo'lishini tekshirish uchun sizga alohida test kerak -
shouldReturnUnknownCommand . Men sizga ushbu testlarni qayta yozishni va tahlil qilishni maslahat beraman. Hozircha jamoalar uchun yarim rasmiy testlar bo'ladi, ammo ular yozilishi kerak. Mantiq SendBotMessageService-ni sinab ko'rish bilan bir xil bo'ladi, shuning uchun men umumiy test mantig'ini AbstractCommandTest sinfiga o'tkazaman va har bir maxsus test klassi meros qilib olinadi va unga kerakli maydonlarni belgilaydi. Barcha testlar bir xil bo'lgani uchun, har safar bir xil narsani yozish oson emas, bundan tashqari, bu yaxshi kod belgisi emas. Umumlashtirilgan mavhum sinf shunday chiqdi:
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.bot.JavarushTelegramBot;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.SendBotMessageServiceImpl;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.mockito.internal.verification.VerificationModeFactory;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
abstract class AbstractCommandTest {
protected JavarushTelegramBot javarushBot = Mockito.mock(JavarushTelegramBot.class);
protected SendBotMessageService sendBotMessageService = new SendBotMessageServiceImpl(javarushBot);
abstract String getCommandName();
abstract String getCommandMessage();
abstract Command getCommand();
@Test
public void shouldProperlyExecuteCommand() throws TelegramApiException {
Long chatId = 1234567824356L;
Update update = new Update();
Message message = Mockito.mock(Message.class);
Mockito.when(message.getChatId()).thenReturn(chatId);
Mockito.when(message.getText()).thenReturn(getCommandName());
update.setMessage(message);
SendMessage sendMessage = new SendMessage();
sendMessage.setChatId(chatId.toString());
sendMessage.setText(getCommandMessage());
sendMessage.enableHtml(true);
getCommand().execute(update);
Mockito.verify(javarushBot).execute(sendMessage);
}
}
Ko'rib turganingizdek, bizda uchta mavhum usul mavjud, qaysi buyruqni aniqlagandan so'ng, bu erda yozilgan testni bajarishi va to'g'ri bajarilishi kerak. Bu shunday qulay yondashuv, agar asosiy mantiq mavhum sinfda bo'lsa, lekin tafsilotlar avlodlarda aniqlangan. Va bu erda, aslida, maxsus testlarni amalga oshirish:
HelpCommandTest:
package com.github.javarushcommunity.jrtb.command;
import org.junit.jupiter.api.DisplayName;
import static com.github.javarushcommunity.jrtb.command.CommandName.HELP;
import static com.github.javarushcommunity.jrtb.command.HelpCommand.HELP_MESSAGE;
@DisplayName("Unit-level testing for HelpCommand")
public class HelpCommandTest extends AbstractCommandTest {
@Override
String getCommandName() {
return HELP.getCommandName();
}
@Override
String getCommandMessage() {
return HELP_MESSAGE;
}
@Override
Command getCommand() {
return new HelpCommand(sendBotMessageService);
}
}
NoCommandTest:
package com.github.javarushcommunity.jrtb.command;
import org.junit.jupiter.api.DisplayName;
import static com.github.javarushcommunity.jrtb.command.CommandName.NO;
import static com.github.javarushcommunity.jrtb.command.NoCommand.NO_MESSAGE;
@DisplayName("Unit-level testing for NoCommand")
public class NoCommandTest extends AbstractCommandTest {
@Override
String getCommandName() {
return NO.getCommandName();
}
@Override
String getCommandMessage() {
return NO_MESSAGE;
}
@Override
Command getCommand() {
return new NoCommand(sendBotMessageService);
}
}
StartCommandTest:
package com.github.javarushcommunity.jrtb.command;
import org.junit.jupiter.api.DisplayName;
import static com.github.javarushcommunity.jrtb.command.CommandName.START;
import static com.github.javarushcommunity.jrtb.command.StartCommand.START_MESSAGE;
@DisplayName("Unit-level testing for StartCommand")
class StartCommandTest extends AbstractCommandTest {
@Override
String getCommandName() {
return START.getCommandName();
}
@Override
String getCommandMessage() {
return START_MESSAGE;
}
@Override
Command getCommand() {
return new StartCommand(sendBotMessageService);
}
}
StopCommandTest:
package com.github.javarushcommunity.jrtb.command;
import org.junit.jupiter.api.DisplayName;
import static com.github.javarushcommunity.jrtb.command.CommandName.STOP;
import static com.github.javarushcommunity.jrtb.command.StopCommand.STOP_MESSAGE;
@DisplayName("Unit-level testing for StopCommand")
public class StopCommandTest extends AbstractCommandTest {
@Override
String getCommandName() {
return STOP.getCommandName();
}
@Override
String getCommandMessage() {
return STOP_MESSAGE;
}
@Override
Command getCommand() {
return new StopCommand(sendBotMessageService);
}
}
UnknownCommandTest:
package com.github.javarushcommunity.jrtb.command;
import org.junit.jupiter.api.DisplayName;
import static com.github.javarushcommunity.jrtb.command.UnknownCommand.UNKNOWN_MESSAGE;
@DisplayName("Unit-level testing for UnknownCommand")
public class UnknownCommandTest extends AbstractCommandTest {
@Override
String getCommandName() {
return "/fdgdfgdfgdbd";
}
@Override
String getCommandMessage() {
return UNKNOWN_MESSAGE;
}
@Override
Command getCommand() {
return new UnknownCommand(sendBotMessageService);
}
}
O'yin shamga arzigulik ekanligi aniq va AbstractCommandTest tufayli biz yozish oson va tushunarli bo'lgan oddiy va tushunarli testlar bilan yakunlandik. Bundan tashqari, biz kodni keraksiz takrorlashdan xalos bo'ldik (DRY-ga salom -> O'zingizni takrorlamang). Bundan tashqari, endi bizda haqiqiy sinovlar mavjud bo'lib, ular yordamida dasturning ishlashini baholay olamiz. Botning o'zi uchun test yozish ham yaxshi bo'lardi, lekin hamma narsa osonlikcha ishlamaydi va umuman olganda, o'yin, ular aytganidek, shamga loyiq emas. Shuning uchun, bu bosqichda biz o'z vazifamizni bajaramiz. Oxirgi va sevimli narsa - biz majburiyat yaratamiz, deb yozadi xabar:
JRTB-3: Telegram Bot buyruqlarini boshqarish uchun qo'shilgan buyruq namunasi Va odatdagidek - Github allaqachon biladi va tortish so'rovini yaratishni taklif qiladi:
Qurilish o'tdi va siz allaqachon qila olasiz. birlash... Lekin yo'q! Loyiha versiyasini yangilashni va uni RELEASE_NOTES da yozishni unutibman. Biz yangi versiya bilan yozuvni qo'shamiz - 0.2.0-SNAPSHOT:
Biz ushbu versiyani pom.xml da yangilaymiz va yangi majburiyat yaratamiz: Yangi topshiriq
:
JRTB-3: yangilangan RELEASE_NOTES.md Endi bosing va qurish tugashini kuting. Qurilish o'tdi, siz uni birlashtira olasiz:
men filialni o'chirmayapman, shuning uchun siz har doim nima o'zgarganini ko'rishingiz va solishtirishingiz mumkin. Bizning vazifalar paneli yangilandi:
xulosalar
Bugun biz katta ish qildik: ish uchun buyruq shablonini taqdim etdik. Hamma narsa sozlangan va endi yangi jamoani qo'shish oddiy va tushunarli jarayon bo'ladi. Bugun test haqida ham gaplashdik. Biz hatto jamoalar uchun turli testlarda kodni takrorlamaslik bilan biroz o'ynadik.
Odatdagidek, men GitHub-da ro'yxatdan o'tishni va ushbu seriyani va u erda ishlayotgan boshqa loyihalarni kuzatish uchun o'z hisobimni kuzatishni taklif qilaman. Men telegram kanalini ham yaratdim , unda yangi maqolalar chiqarilishini takrorlayman. Qizig'i shundaki, kod odatda maqolaning o'zidan bir hafta oldin chiqariladi va men har safar yangi vazifa bajarilganda yozaman, bu menga maqolani o'qishdan oldin kodni aniqlash imkoniyatini beradi. Tez orada men botni doimiy ravishda nashr etaman va telegram kanaliga obuna bo'lganlar bu haqda birinchilardan bo'lib xabardor bo'lishadi ;) O'qiganingiz uchun barchangizga rahmat, davomi.
GO TO FULL VERSION