JavaRush /Java блогы /Random-KK /Ботпен жұмыс істеу үшін Пәрмен үлгісін іске асырайық. (2 ...
Roman Beekeeper
Деңгей

Ботпен жұмыс істеу үшін Пәрмен үлгісін іске асырайық. (2 бөлім) - «Java жобасы А-дан Я-ға дейін»

Топта жарияланған

Біз қолданбаға тесттер жазамыз

Мақаланың басы: JRTB-3 жазу . Енді тестілеу туралы ойлануымыз керек. Функционалдық біз күткендей жұмыс істейтініне сенімді болу үшін барлық қосылған code сынақтармен қамтылуы керек. Алдымен SendBotMessageService қызметі үшін бірлік сынақтарын жазамыз.
Бірлік сынағы қолданбаның кейбір шағын бөлігінің логикасын тексеретін сынақ: әдетте бұл әдістер. Және бұл әдіске ие барлық қосылымдар мазақтардың көмегімен жалғанға ауыстырылады.
Енді бәрін көресіз. Сол пакетте, тек ./src/test/java қалтасында біз сынайтын сыныппен бірдей атаумен класс жасаймыз және соңында Test қосамыз . Яғни, SendBotMessageService үшін бізде осы сыныпқа арналған барлық сынақтарды қамтитын SendBotMessageServiceTest болады . Оны тестілеудегі идея келесідей: біз жалған (жалған) JavaRushTelegarmBot-қа енеміз, содан кейін біз орындау әдісі осындай аргументпен шақырылды ма, жоқ па деп сұраймыз. Міне, оқиға:
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 {
       //given
       String chatId = "test_chat_id";
       String message = "test_message";

       SendMessage sendMessage = new SendMessage();
       sendMessage.setText(message);
       sendMessage.setChatId(chatId);
       sendMessage.enableHtml(true);

       //when
       sendBotMessageService.sendMessage(chatId, message);

       //then
       Mockito.verify(javarushBot).execute(sendMessage);
   }
}
Mockito көмегімен мен жалған JavaRushBot нысанын жасадым, мен оны қызметіміздің конструкторына бердім. Содан кейін мен бір тест жаздым (Тест annotationсы бар әрбір әдіс жеке сынақ болып табылады). Бұл әдістің құрылымы әрқашан бірдей - ол ешқандай аргументтерді қажет етпейді және бос мәнді қайтарады. Сынақ атауы не сынап жатқанымызды көрсетуі керек. Біздің жағдайда бұл: хабарламаны дұрыс жіберу керек - хабарламаны дұрыс жіберу керек. Біздің тестіміз үш бөлікке бөлінеді:
  • блок //берілген - мұнда біз тестке қажеттінің бәрін дайындаймыз;
  • блок //қашан - тестілеуді жоспарлаған әдісті іске қосамыз;
  • //содан кейін блок - мұнда әдіс дұрыс жұмыс істегенін тексереміз.
Біздің қызметтегі логика әзірге қарапайым болғандықтан, осы сыныпқа бір сынақ жеткілікті болады. Енді CommandContainer үшін тест жазамыз:
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() {
       //when-then
       Arrays.stream(CommandName.values())
               .forEach(commandName -> {
                   Command command = commandContainer.retrieveCommand(commandName.getCommandName());
                   Assertions.assertNotEquals(UnknownCommand.class, command.getClass());
               });
   }

   @Test
   public void shouldReturnUnknownCommand() {
       //given
       String unknownCommand = "/fgjhdfgdfg";

       //when
       Command command = commandContainer.retrieveCommand(unknownCommand);

       //then
       Assertions.assertEquals(UnknownCommand.class, command.getClass());
   }
}
Бұл өте айқын сынақ емес. Ол контейнер логикасына сүйенеді. Бот қолдайтын барлық пәрмендер CommandName тізімінде және контейнерде болуы керек. Сондықтан мен барлық CommandName айнымалыларын алдым, Stream API-ге бардым және әрқайсысы үшін контейнерден пәрмен іздедім. Егер мұндай пәрмен болмаса, Белгісіз пәрмен қайтарылады. Бұл жолда біз мынаны тексереміз:
Assertions.assertNotEquals(UnknownCommand.class, command.getClass());
UnknownCommand әдепкі болатынын тексеру үшін сізге бөлек сынақ қажет - shouldReturnUnknownCommand . Мен сізге осы сынақтарды қайта жазуға және талдауға кеңес беремін. Әзірге командалар үшін жартылай ресми сынақтар болады, бірақ оларды жазу керек. Логика SendBotMessageService сынағымен бірдей болады, сондықтан мен жалпы сынақ логикасын AbstractCommandTest сыныбына жылжытамын және әрбір нақты сынақ сыныбы мұраланып, оған қажет өрістерді анықтайды. Барлық сынақтар бір типті болғандықтан, әр уақытта бірдей нәрсені жазу оңай емес, сонымен қатар бұл жақсы codeтың белгісі емес. Жалпыланған дерексіз класс осылай болды:
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 for testing {@link Command}s.
*/
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 {
       //given
       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);

       //when
       getCommand().execute(update);

       //then
       Mockito.verify(javarushBot).execute(sendMessage);
   }
}
Көріп отырғаныңыздай, бізде үш дерексіз әдіс бар, оны анықтағаннан кейін әрбір команда осында жазылған сынақты іске қосып, дұрыс орындауы керек. Бұл негізгі логика абстрактілі класста болған кезде, бірақ егжей-тегжейлер ұрпақтарда анықталған кезде ыңғайлы тәсіл. Міне, нақты сынақтардың орындалуы:

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);
   }
}
Ойынның шамға тұрарлық екені анық және AbstractCommandTest арқасында біз жазуға оңай және түсінуге оңай қарапайым және түсінікті сынақтармен аяқталдық. Сонымен қатар, біз codeты қажетсіз қайталаудан құтылдық (ҚҰРҒУ -> Өзіңізді қайталамау принципіне сәлем). Сонымен қатар, қазір бізде қосымшаның өнімділігін бағалай алатын нақты сынақтар бар. Сондай-ақ, боттың өзі үшін тест жазу жақсы болар еді, бірақ бәрі оңай болмайды және жалпы алғанда, олар айтқандай, ойын шамға тұрарлық емес шығар. Сондықтан бұл кезеңде тапсырмамызды орындаймыз. Соңғы және сүйікті нәрсе - біз міндеттеме жасаймыз, хабарлама жазады: JRTB-3: Telegram Bot командаларын өңдеуге арналған пәрмен үлгісі қосылды Және әдеттегідей - Github бұрыннан біледі және тарту сұрауын жасауды ұсынады: «А-дан Я-ға Java жобасы»: ботпен жұмыс істеуге арналған пәрмен үлгісін енгізу.  2 - 1 бөлімқұрастыру өтті және сіз қазірдің өзінде жасай аласыз. біріктіру... Бірақ жоқ! Мен жоба нұсқасын жаңартуды және оны RELEASE_NOTES ішінде жазуды ұмытып қалдым. Біз жаңа нұсқасы бар жазбаны қосамыз - 0.2.0-SNAPSHOT: «А-дан Я-ға Java жобасы»: ботпен жұмыс істеуге арналған пәрмен үлгісін енгізу.  2 - 2 бөлімБұл нұсқаны pom.xml ішінде жаңартамыз және жаңа міндеттеме жасаймыз: «А-дан Я-ға Java жобасы»: ботпен жұмыс істеуге арналған пәрмен үлгісін енгізу.  2 - 3 бөлімЖаңа міндеттеме: JRTB-3: жаңартылған RELEASE_NOTES.md«А-дан Я-ға Java жобасы»: ботпен жұмыс істеуге арналған пәрмен үлгісін енгізу.  2 - 4 бөлім Енді итеріп, құрастырудың аяқталуын күтіңіз. Құрылым аяқталды, сіз оны біріктіре аласыз: «А-дан Я-ға Java жобасы»: ботпен жұмыс істеуге арналған пәрмен үлгісін енгізу.  2 - 5 бөліммен тармақты жоймаймын, сондықтан сіз әрқашан не өзгергенін қарап, салыстыра аласыз. Тапсырмалар тақтасы жаңартылды:«А-дан Я-ға Java жобасы»: ботпен жұмыс істеуге арналған пәрмен үлгісін енгізу.  2 - 6 бөлім

қорытындылар

Бүгін біз үлкен нәрсе жасадық: жұмыс үшін команда үлгісін енгіздік. Барлығы реттелді, енді жаңа команда қосу қарапайым және қарапайым процесс болады. Біз бүгін тестілеу туралы да айттық. Біз командалар үшін әртүрлі сынақтарда codeты қайталамай біраз ойнадық. Әдеттегідей, мен GitHub сайтында тіркелуді және осы серияны және мен онда жұмыс істеп жатқан басқа жобаларды қадағалау үшін тіркелгімді орындауды ұсынамын. Мен сондай-ақ жаңа мақалалар шығарылымын қайталайтын телеграм арнасын құрдым . Бір қызығы, code әдетте мақаланың өзінен бір апта бұрын шығарылады, мен арнада мен мақаланы оқымас бұрын codeты анықтауға мүмкіндік беретін жаңа тапсырма аяқталған сайын жазамын. Жақында мен ботты тұрақты түрде шығаратын боламын, ал телеграм каналына жазылғандар бұл туралы бірінші болып біледі ;) Оқығандарыңызға рахмет, жалғасы.

Сериядағы барлық материалдардың тізімі осы мақаланың басында.

Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION