JavaRush /Blog Java /Random-MS /Mari kita laksanakan Corak Perintah untuk bekerja dengan ...

Mari kita laksanakan Corak Perintah untuk bekerja dengan bot. (Bahagian 2) - "Projek Java dari A hingga Z"

Diterbitkan dalam kumpulan

Kami menulis ujian untuk permohonan itu

Permulaan artikel: menulis JRTB-3 . Sekarang kita perlu berfikir tentang ujian. Semua kod yang ditambahkan harus diliputi dengan ujian supaya kami dapat memastikan bahawa fungsi berfungsi seperti yang kami harapkan. Mula-mula kita akan menulis ujian unit untuk perkhidmatan SendBotMessageService.
Ujian unit ialah ujian yang menguji logik beberapa bahagian kecil aplikasi: biasanya ini adalah kaedah. Dan semua sambungan yang mempunyai kaedah ini digantikan dengan yang palsu menggunakan olok-olok.
Sekarang anda akan melihat segala-galanya. Dalam pakej yang sama, hanya dalam folder ./src/test/java , kami mencipta kelas dengan nama yang sama dengan kelas yang akan kami uji dan menambah Ujian pada penghujung . Iaitu, untuk SendBotMessageService kita akan mempunyai SendBotMessageServiceTest , yang akan mengandungi semua ujian untuk kelas ini. Idea dalam mengujinya adalah seperti berikut: kami menyelitkan JavaRushTelegarmBot olok-olok (palsu), yang kemudian kami tanya sama ada kaedah laksana dipanggil dengan hujah sedemikian atau tidak. Inilah yang berlaku:
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);
   }
}
Menggunakan Mockito, saya mencipta objek JavaRushBot olok-olok, yang saya berikan kepada pembina perkhidmatan kami. Seterusnya, saya menulis satu ujian (setiap kaedah dengan anotasi Ujian adalah ujian berasingan). Struktur kaedah ini sentiasa sama - ia tidak memerlukan hujah dan mengembalikan tidak sah. Nama ujian harus memberitahu anda perkara yang kami uji. Dalam kes kami, ini ialah: harus menghantar mesej dengan betul - mesti menghantar mesej dengan betul. Ujian kami dibahagikan kepada tiga bahagian:
  • blok //diberikan - di mana kami menyediakan semua yang diperlukan untuk ujian;
  • blok //bila - tempat kami melancarkan kaedah yang kami rancang untuk menguji;
  • //kemudian blok - di mana kita menyemak sama ada kaedah itu berfungsi dengan betul.
Memandangkan logik dalam perkhidmatan kami adalah mudah setakat ini, satu ujian untuk kelas ini sudah memadai. Sekarang mari kita tulis ujian untuk 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());
   }
}
Ini bukan ujian yang sangat jelas. Ia bergantung pada logik bekas. Semua arahan yang disokong bot adalah dalam senarai CommandName dan mesti berada dalam bekas. Jadi saya mengambil semua pembolehubah CommandName, pergi ke API Strim dan untuk setiap satu saya mencari arahan daripada bekas. Jika tiada arahan sedemikian, UnknownCommand akan dikembalikan. Inilah yang kami semak dalam baris ini:
Assertions.assertNotEquals(UnknownCommand.class, command.getClass());
Dan untuk menyemak bahawa UnknownCommand akan menjadi lalai, anda memerlukan ujian berasingan - shouldReturnUnknownCommand . Saya menasihati anda untuk menulis semula dan menganalisis ujian ini. Akan ada ujian separa formal untuk pasukan buat masa ini, tetapi mereka perlu ditulis. Logiknya akan sama seperti untuk menguji SendBotMessageService, jadi saya akan memindahkan logik ujian umum ke dalam kelas AbstractCommandTest, dan setiap kelas ujian tertentu akan diwarisi dan mentakrifkan medan yang diperlukannya. Memandangkan semua ujian adalah daripada jenis yang sama, menulis perkara yang sama setiap kali bukanlah mudah, ditambah ini bukan tanda kod yang baik. Beginilah rupa kelas abstrak umum:
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);
   }
}
Seperti yang anda lihat, kami mempunyai tiga kaedah abstrak, selepas menentukan setiap arahan yang harus menjalankan ujian yang ditulis di sini dan dilaksanakan dengan betul. Ini adalah pendekatan yang mudah apabila logik utama berada dalam kelas abstrak, tetapi butirannya ditakrifkan dalam keturunan. Dan di sini, sebenarnya, adalah pelaksanaan ujian 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);
   }
}
Jelas sekali bahawa permainan ini sangat berharga, dan terima kasih kepada AbstractCommandTest, kami mendapat ujian yang ringkas dan mudah difahami yang mudah ditulis dan mudah difahami. Di samping itu, kami menyingkirkan pertindihan kod yang tidak perlu (hello kepada prinsip KERING -> Jangan Ulangi Diri Sendiri). Di samping itu, kini kami mempunyai ujian sebenar yang mana kami boleh menilai prestasi aplikasi. Ia juga bagus untuk menulis ujian untuk bot itu sendiri, tetapi semuanya tidak akan berjalan dengan mudah dan secara umum, mungkin permainan itu tidak bernilai, seperti yang mereka katakan. Oleh itu, pada peringkat ini kami akan menyelesaikan tugas kami. Perkara terakhir dan kegemaran - kami membuat komit, menulis mesej: JRTB-3: menambah Corak arahan untuk mengendalikan arahan Bot Telegram Dan seperti biasa - Github sudah tahu dan menawarkan untuk membuat permintaan tarik: "Projek Java dari A hingga Z": Melaksanakan Corak Perintah untuk bekerja dengan bot.  Bahagian 2 - 1Binaan telah berlalu dan anda sudah boleh bergabung... Tetapi tidak! Saya terlupa untuk mengemas kini versi projek dan menulisnya dalam RELEASE_NOTES. Kami menambah entri dengan versi baharu - 0.2.0-SNAPSHOT: "Projek Java dari A hingga Z": Melaksanakan Corak Perintah untuk bekerja dengan bot.  Bahagian 2 - 2Kami mengemas kini versi ini dalam pom.xml dan mencipta komit baharu: "Projek Java dari A hingga Z": Melaksanakan Corak Perintah untuk bekerja dengan bot.  Bahagian 2 - 3Komit baharu: JRTB-3: dikemas kini RELEASE_NOTES.md"Projek Java dari A hingga Z": Melaksanakan Corak Perintah untuk bekerja dengan bot.  Bahagian 2 - 4 Sekarang tolak dan tunggu binaan selesai. Binaan telah berlalu, anda boleh menggabungkannya: "Java-проект от А до Я": Реализуем Command Pattern для работы с ботом. Часть 2 - 5Saya tidak memadamkan cawangan, jadi anda sentiasa boleh melihat dan membandingkan apa yang telah berubah. Papan tugas kami telah dikemas kini:"Java-проект от А до Я": Реализуем Command Pattern для работы с ботом. Часть 2 - 6

kesimpulan

Hari ini kami melakukan perkara yang besar: kami memperkenalkan templat Perintah untuk bekerja. Segala-galanya telah disediakan, dan kini menambah pasukan baharu akan menjadi proses yang mudah dan mudah. Kami juga bercakap tentang ujian hari ini. Kami juga bermain sedikit dengan tidak mengulangi kod dalam ujian yang berbeza untuk pasukan. Seperti biasa, saya cadangkan mendaftar di GitHub dan mengikuti akaun saya untuk mengikuti siri ini dan projek lain yang sedang saya usahakan di sana. Saya juga mencipta saluran telegram di mana saya akan menduplikasi keluaran artikel baharu. Satu perkara yang menarik ialah kod itu biasanya dikeluarkan seminggu sebelum artikel itu sendiri, dan pada saluran saya akan menulis setiap kali tugas baru telah selesai, yang akan memberi saya peluang untuk memikirkan kod sebelum membaca artikel. Tidak lama lagi saya akan menerbitkan bot itu secara berterusan, dan mereka yang melanggan saluran telegram akan menjadi orang pertama yang mengetahui tentangnya ;) Terima kasih semua kerana membaca, akan diteruskan.

Senarai semua bahan dalam siri ini adalah pada permulaan artikel ini.

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