JavaRush /Java Blogu /Random-AZ /Gəlin botla işləmək üçün Əmr Modelini həyata keçirək. (2-...
Roman Beekeeper
Səviyyə

Gəlin botla işləmək üçün Əmr Modelini həyata keçirək. (2-ci hissə) - "A-dan Z-yə Java layihəsi"

Qrupda dərc edilmişdir

Tətbiq üçün testlər yazırıq

Məqalənin başlanğıcı: JRTB-3 yazmaq . İndi test haqqında düşünməliyik. Bütün əlavə edilmiş kodlar testlərlə əhatə olunmalıdır ki, funksionallığın gözlədiyimiz kimi işlədiyinə əmin ola bilək. Əvvəlcə SendBotMessageService xidməti üçün vahid testləri yazacağıq.
Vahid testi tətbiqin bəzi kiçik hissəsinin məntiqini yoxlayan testdir: adətən bunlar üsullardır. Və bu üsula malik olan bütün əlaqələr istehza istifadə edərək saxta olanlarla əvəz olunur.
İndi hər şeyi görəcəksən. Eyni paketdə yalnız ./src/test/java qovluğunda sınayacağımız siniflə eyni adda bir sinif yaradırıq və sonunda Test əlavə edirik . Yəni, SendBotMessageService üçün bizdə bu sinif üçün bütün testləri ehtiva edən SendBotMessageServiceTest olacaq . Sınaqda fikir belədir: biz istehza (saxta) JavaRushTelegarmBot-a daxil oluruq, ondan sonra icra metodunun belə bir arqumentlə çağırılıb-çağrılmadığını soruşuruq. Budur, baş verənlər:
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-dan istifadə edərək, xidmətimizin konstruktoruna ötürdüyüm saxta JavaRushBot obyekti yaratdım. Sonra bir test yazdım (Sınaq annotasiyası olan hər bir üsul ayrıca testdir). Bu metodun strukturu həmişə eynidir - heç bir arqument tələb etmir və boş qaytarır. Test adı sizə nə sınadığımızı bildirməlidir. Bizim vəziyyətimizdə bu: mesajı düzgün göndərməlidir - mesajı düzgün göndərməlidir. Testimiz üç hissəyə bölünür:
  • blok //verilmiş - burada test üçün lazım olan hər şeyi hazırlayırıq;
  • blok //nə vaxt - sınaqdan keçirməyi planlaşdırdığımız metodu işə saldığımız yer;
  • //sonra blok - burada metodun düzgün işlədiyini yoxlayırıq.
Xidmətimizdəki məntiq indiyə qədər sadə olduğundan, bu sinif üçün bir test kifayət edəcəkdir. İndi CommandContainer üçün test yazaq:
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());
   }
}
Bu çox açıq bir sınaq deyil. Konteynerin məntiqinə əsaslanır. Botun dəstəklədiyi bütün əmrlər CommandName siyahısındadır və konteynerdə olmalıdır. Beləliklə, mən bütün CommandName dəyişənlərini götürdüm, Stream API-ə keçdim və hər biri üçün konteynerdən əmr axtardım. Əgər belə bir əmr olmasaydı, Naməlum Əmr qaytarılacaqdı. Bu xəttdə yoxladığımız budur:
Assertions.assertNotEquals(UnknownCommand.class, command.getClass());
UnknownCommand-ın defolt olacağını yoxlamaq üçün ayrıca test lazımdır - shouldReturnUnknownCommand . Mən sizə bu testləri yenidən yazıb təhlil etməyi məsləhət görürəm. Hələlik komandalar üçün yarı-formal testlər olacaq, lakin onları yazmaq lazımdır. Məntiq SendBotMessageService testi ilə eyni olacaq, ona görə də ümumi test məntiqini AbstractCommandTest sinfinə köçürəcəyəm və hər bir xüsusi test sinfi miras alınacaq və ona lazım olan sahələri müəyyənləşdirəcək. Bütün testlər eyni tipli olduğundan, hər dəfə eyni şeyi yazmaq asan deyil, üstəlik, bu yaxşı kodun əlaməti deyil. Ümumiləşdirilmiş mücərrəd sinif belə oldu:
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);
   }
}
Gördüyünüz kimi, üç mücərrəd metodumuz var, hansı əmri müəyyən etdikdən sonra burada yazılan testi yerinə yetirməli və düzgün yerinə yetirməlidir. Bu, əsas məntiq mücərrəd bir sinifdə olduqda belə rahat bir yanaşmadır, lakin detallar nəsillərdə müəyyən edilir. Və burada, əslində, xüsusi testlərin tətbiqi:

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);
   }
}

Naməlum Əmr Testi:

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);
   }
}
Oyunun şama dəyər olduğu aydındır və AbstractCommandTest sayəsində yazması asan və başa düşülən sadə və başa düşülən testlərlə başa çatdıq. Bundan əlavə, lazımsız kod təkrarlanmasından xilas olduq (QURUĞA salam -> Özünü Təkrar etmə prinsipi). Bundan əlavə, indi tətbiqin performansını qiymətləndirə biləcəyimiz real testlərimiz var. Botun özü üçün bir test yazmaq da yaxşı olardı, amma hər şey o qədər də asan olmayacaq və ümumiyyətlə, oyun, necə deyərlər, şama dəyməz. Ona görə də bu mərhələdə biz işimizi tamamlayacağıq. Ən son və sevimli şey - biz bir öhdəlik yaradırıq, mesaj yazır: JRTB-3: Telegram Bot əmrlərini idarə etmək üçün əlavə Əmr nümunəsi Və həmişəki kimi - Github artıq bilir və çəkmə sorğusu yaratmağı təklif edir: "A-dan Z-yə Java layihəsi": Botla işləmək üçün Əmr Modelinin həyata keçirilməsi.  Hissə 2 - 1Quraşdırma keçdi və siz artıq edə bilərsiniz birləşmək... Amma yox! Layihə versiyasını yeniləməyi və RELEASE_NOTES-də yazmağı unutmuşam. Biz yeni versiya ilə bir giriş əlavə edirik - 0.2.0-SNAPSHOT: "A-dan Z-yə Java layihəsi": Botla işləmək üçün Əmr Modelinin həyata keçirilməsi.  2-2 hissəBu versiyanı pom.xml-də yeniləyirik və yeni öhdəlik yaradırıq: "A-dan Z-yə Java layihəsi": Botla işləmək üçün Əmr Modelinin həyata keçirilməsi.  2-3 hissəYeni öhdəlik: JRTB-3: yenilənmiş RELEASE_NOTES.md"A-dan Z-yə Java layihəsi": Botla işləmək üçün Əmr Modelinin həyata keçirilməsi.  2-4 hissə İndi itələyin və quruluşun tamamlanmasını gözləyin. Quraşdırma keçdi, siz onu birləşdirə bilərsiniz: "A-dan Z-yə Java layihəsi": Botla işləmək üçün Əmr Modelinin həyata keçirilməsi.  2-5 hissəMən filialı silmirəm, ona görə də hər zaman nə dəyişdiyini baxıb müqayisə edə bilərsiniz. Tapşırıq lövhəmiz yeniləndi:"A-dan Z-yə Java layihəsi": Botla işləmək üçün Əmr Modelinin həyata keçirilməsi.  2-6 hissə

nəticələr

Bu gün biz böyük bir iş gördük: iş üçün Komanda şablonunu təqdim etdik. Hər şey qurulub və indi yeni komanda əlavə etmək sadə və sadə bir proses olacaq. Bu gün sınaqdan da danışdıq. Hətta komandalar üçün müxtəlif testlərdə kodu təkrarlamamaqla bir az oynadıq. Həmişə olduğu kimi, bu seriyanı və orada işlədiyim digər layihələri izləmək üçün GitHub-da qeydiyyatdan keçməyi və hesabımı izləməyi təklif edirəm . Mən də yeni məqalələrin buraxılışını təkrarlayacağım bir teleqram kanalı yaratdım. Maraqlısı odur ki, kod adətən məqalənin özündən bir həftə əvvəl buraxılır və kanalda hər dəfə yeni tapşırığın tamamlandığını yazacağam ki, bu da mənə məqaləni oxumazdan əvvəl kodu anlamaq imkanı verəcək. Tezliklə botu davamlı olaraq dərc edəcəm və telegram kanalına abunə olanlar bundan ilk xəbərdar olacaqlar ;) Oxuduğunuz üçün hamınıza təşəkkür edirəm, davamı olsun.

Serialdakı bütün materialların siyahısı bu məqalənin əvvəlindədir.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION