JavaRush /Blog Jawa /Random-JV /Ayo ngleksanakake Pola Komando kanggo nggarap bot. (Bagia...

Ayo ngleksanakake Pola Komando kanggo nggarap bot. (Bagian 2) - "Proyek Jawa saka A nganti Z"

Diterbitake ing grup

Kita nulis tes kanggo aplikasi kasebut

Wiwitan artikel: nulis JRTB-3 . Saiki kita kudu mikir babagan tes. Kabeh kode sing ditambahake kudu dijamin karo tes supaya kita bisa mesthekake yen fungsi kasebut bisa digunakake kaya sing dikarepake. Pisanan kita bakal nulis tes unit kanggo layanan SendBotMessageService.
Tes unit minangka tes sing nguji logika sawetara bagean cilik saka aplikasi: biasane iki minangka metode. Lan kabeh sambungan sing duwe cara iki diganti karo sing palsu nggunakake mock.
Saiki sampeyan bakal weruh kabeh. Ing paket sing padha, mung ing folder ./src/test/java , kita nggawe kelas kanthi jeneng sing padha karo kelas sing bakal diuji, lan nambah Test ing pungkasan . Yaiku, kanggo SendBotMessageService kita bakal duwe SendBotMessageServiceTest , sing bakal ngemot kabeh tes kanggo kelas iki. Gagasan kanggo nguji kaya ing ngisor iki: kita mlebu ing JavaRushTelegarmBot mock (palsu), sing banjur takon apa metode eksekusi kasebut diarani kanthi argumen kasebut utawa ora. Mangkene kedadeyane:
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);
   }
}
Nggunakake Mockito, aku nggawe obyek JavaRushBot mock, sing dakterusake menyang konstruktor layanan kita. Sabanjure, aku nulis siji tes (saben cara kanthi anotasi Test minangka tes sing kapisah). Struktur cara iki tansah padha - ora njupuk bantahan lan bali roso sepi. Jeneng tes kudu menehi katrangan babagan apa sing dites. Ing kasus kita, iki: ngirim pesen kanthi bener - kudu ngirim pesen kanthi bener. Tes kita dipérang dadi telung bagean:
  • blok // diwenehi - ngendi kita nyiapake kabeh sing perlu kanggo test;
  • pemblokiran // nalika - ngendi kita miwiti cara sing kita rencana kanggo nyoba;
  • // banjur mblokir - ngendi kita mriksa apa cara bisa digunakake kanthi bener.
Wiwit logika ing layanan kita prasaja nganti saiki, siji test kanggo kelas iki bakal cukup. Saiki ayo nulis tes kanggo 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());
   }
}
Iki dudu tes sing jelas banget. Iku gumantung ing logika wadhah. Kabeh printah sing didhukung bot ana ing dhaptar CommandName lan kudu ana ing wadhah kasebut. Dadi aku njupuk kabeh variabel CommandName, pindhah menyang Stream API lan kanggo saben aku nggolèki printah saka wadhah. Yen ora ana prentah kasebut, UnknownCommand bakal bali. Iki sing kita priksa ing baris iki:
Assertions.assertNotEquals(UnknownCommand.class, command.getClass());
Lan kanggo mriksa manawa UnknownCommand bakal dadi standar, sampeyan butuh tes sing kapisah - shouldReturnUnknownCommand . Aku menehi saran supaya sampeyan nulis maneh lan nganalisa tes kasebut. Saiki bakal ana tes semi-formal kanggo tim, nanging kudu ditulis. Logika bakal padha karo kanggo testing SendBotMessageService, supaya aku bakal mindhah logika test umum menyang kelas AbstractCommandTest, lan saben kelas test tartamtu bakal diwenehi warisan lan nemtokake lapangan iku perlu. Wiwit kabeh tes saka jinis padha, nulis bab sing padha saben wektu ora gampang, plus iki ora tandha kode apik. Mangkene carane kelas abstrak umum dadi:
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);
   }
}
Kaya sing sampeyan ngerteni, kita duwe telung cara abstrak, sawise nemtokake manawa saben printah kudu mbukak tes sing ditulis ing kene lan dieksekusi kanthi bener. Iki minangka pendekatan sing trep nalika logika utama ana ing kelas abstrak, nanging rincian kasebut ditetepake ing keturunan. Lan ing kene, nyatane, ana implementasi tes khusus:

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);
   }
}
Cetha yen game kasebut ana regane lilin, lan thanks kanggo AbstractCommandTest rampung karo tes sing gampang lan gampang dingerteni sing gampang ditulis lan gampang dingerteni. Kajaba iku, kita nyingkirake duplikasi kode sing ora perlu (halo kanggo prinsip KERING -> Aja Ulangi Dhewe). Kajaba iku, saiki kita duwe tes nyata sing bisa ngadili kinerja aplikasi kasebut. Iku uga apik kanggo nulis test kanggo bot dhewe, nanging kabeh ora bakal bisa metu supaya gampang lan ing umum, Mungkin game ora worth lilin, lagi ngomong. Mula, ing tahap iki kita bakal ngrampungake tugas kita. Sing paling pungkasan lan paling disenengi - kita nggawe komitmen, nulis pesen: JRTB-3: ditambahake Pola komando kanggo nangani perintah Telegram Bot Lan kaya biasane - Github wis ngerti lan nawakake kanggo nggawe panjaluk tarik: "Proyek Jawa saka A nganti Z": Ngleksanakake Pola Perintah kanggo nggarap bot.  Bagean 2 - 1Mbangun wis liwati lan sampeyan wis bisa gabung... Nanging ora! Aku kelalen nganyari versi proyek lan nulis ing RELEASE_NOTES. Kita nambah entri karo versi anyar - 0.2.0-SNAPSHOT: "Proyek Jawa saka A nganti Z": Ngleksanakake Pola Perintah kanggo nggarap bot.  Bagean 2 - 2Kita nganyari versi iki ing pom.xml lan nggawe komitmen anyar: "Proyek Jawa saka A nganti Z": Ngleksanakake Pola Perintah kanggo nggarap bot.  Bagean 2 - 3New commit: JRTB-3: dianyari RELEASE_NOTES.md"Proyek Jawa saka A nganti Z": Ngleksanakake Pola Perintah kanggo nggarap bot.  Bagean 2 - 4 Saiki push lan ngenteni mbangun rampung. Mbangun wis liwati, sampeyan bisa nggabungake: "Proyek Jawa saka A nganti Z": Ngleksanakake Pola Perintah kanggo nggarap bot.  Bagean 2 - 5Aku ora mbusak cabang, supaya sampeyan bisa tansah katon lan mbandhingaké apa wis diganti. Papan tugas kita wis dianyari:"Proyek Jawa saka A nganti Z": Ngleksanakake Pola Perintah kanggo nggarap bot.  Bagean 2 - 6

kesimpulan

Dina iki kita nindakake bab gedhe: kita ngenalaken Cithakan Command kanggo karya. Kabeh wis diatur, lan saiki nambah tim anyar bakal dadi proses sing prasaja lan langsung. Kita uga ngomong babagan tes dina iki. Kita malah muter sethitik karo ora mbaleni kode ing tes beda kanggo tim. Kaya biasane, aku saranake ndhaptar ing GitHub lan tindakake akunku kanggo ngetutake seri iki lan proyek liyane sing lagi dakgarap ing kana. Aku uga nggawe saluran telegram sing bakal nggawe duplikat rilis artikel anyar. Siji bab sing menarik yaiku kode kasebut biasane dirilis seminggu sadurunge artikel kasebut dhewe, lan ing saluran kasebut aku bakal nulis saben tugas anyar wis rampung, sing bakal menehi kesempatan kanggo ngerteni kode kasebut sadurunge maca artikel kasebut. Sakcepete aku bakal nerbitake bot kasebut kanthi terus-terusan, lan sing langganan saluran telegram bakal dadi sing pertama ngerti babagan iki;) Matur nuwun kanggo kabeh sing wis maca, bakal diterusake.

Dhaptar kabeh materi ing seri kasebut ana ing wiwitan artikel iki.

Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION