Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- From 69e258f0086d811f7f7b6862bce7ee582f766b4e Mon Sep 17 00:00:00 2001
- From: Zabuzard <[email protected]>
- Date: Wed, 29 Sep 2021 17:31:38 +0200
- Subject: [PATCH] Added JDA mock and tests
- ---
- application/build.gradle | 2 +
- .../togetherjava/tjbot/AbstractJdaMock.java | 109 +++++++++++++
- .../tjbot/command/DatabaseCommandTest.java | 144 ++++++++++++++++++
- .../tjbot/command/PingCommandTest.java | 38 +++++
- 4 files changed, 293 insertions(+)
- create mode 100644 application/src/test/java/org/togetherjava/tjbot/AbstractJdaMock.java
- create mode 100644 application/src/test/java/org/togetherjava/tjbot/command/DatabaseCommandTest.java
- create mode 100644 application/src/test/java/org/togetherjava/tjbot/command/PingCommandTest.java
- diff --git a/application/build.gradle b/application/build.gradle
- index 6f02cf7..056aef4 100644
- --- a/application/build.gradle
- +++ b/application/build.gradle
- @@ -50,6 +50,8 @@ dependencies {
- implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.5'
- + testImplementation 'org.mockito:mockito-core:3.12.4'
- + testRuntimeOnly 'org.mockito:mockito-core:3.12.4'
- testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
- testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
- }
- diff --git a/application/src/test/java/org/togetherjava/tjbot/AbstractJdaMock.java b/application/src/test/java/org/togetherjava/tjbot/AbstractJdaMock.java
- new file mode 100644
- index 0000000..f82c35c
- --- /dev/null
- +++ b/application/src/test/java/org/togetherjava/tjbot/AbstractJdaMock.java
- @@ -0,0 +1,109 @@
- +package org.togetherjava.tjbot;
- +
- +import net.dv8tion.jda.api.entities.SelfUser;
- +import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
- +import net.dv8tion.jda.api.requests.restaction.MessageAction;
- +import net.dv8tion.jda.api.utils.ConcurrentSessionController;
- +import net.dv8tion.jda.api.utils.data.DataObject;
- +import net.dv8tion.jda.internal.JDAImpl;
- +import net.dv8tion.jda.internal.entities.EntityBuilder;
- +import net.dv8tion.jda.internal.entities.PrivateChannelImpl;
- +import net.dv8tion.jda.internal.entities.SelfUserImpl;
- +import net.dv8tion.jda.internal.entities.UserImpl;
- +import net.dv8tion.jda.internal.interactions.CommandInteractionImpl;
- +import net.dv8tion.jda.internal.interactions.InteractionHookImpl;
- +import net.dv8tion.jda.internal.requests.Requester;
- +import net.dv8tion.jda.internal.requests.restaction.MessageActionImpl;
- +import net.dv8tion.jda.internal.requests.restaction.interactions.ReplyActionImpl;
- +import net.dv8tion.jda.internal.utils.config.AuthorizationConfig;
- +import org.junit.jupiter.api.BeforeEach;
- +import org.mockito.Mockito;
- +import org.slf4j.Logger;
- +import org.slf4j.LoggerFactory;
- +
- +import javax.annotation.Nonnull;
- +import java.util.concurrent.ScheduledThreadPoolExecutor;
- +
- +import static org.mockito.ArgumentMatchers.any;
- +import static org.mockito.ArgumentMatchers.anyLong;
- +import static org.mockito.ArgumentMatchers.anyString;
- +import static org.mockito.Mockito.doReturn;
- +import static org.mockito.Mockito.mock;
- +import static org.mockito.Mockito.when;
- +
- +/**
- + * This class mocks a valid JDA instance with a user, an api and a message channel mock
- + * implementations
- + */
- +public abstract class AbstractJdaMock {
- +
- + private final long userId;
- + private final long applicationId;
- + protected static final Logger logger = LoggerFactory.getLogger(AbstractJdaMock.class);
- + /**
- + * is a mock on which we can stub out methods and simulate a real JDA instance that can send
- + * messages to the bot
- + */
- + protected JDAImpl jdaImplMock;
- + /**
- + * is spied upon to validate actions performed by the bot
- + */
- + protected PrivateChannelImpl privateChannel;
- +
- + public AbstractJdaMock(long userId, long applicationId) {
- + this.userId = userId;
- + this.applicationId = applicationId;
- + }
- +
- + // TODO - Improve these mocks. Some of them could actually be the real concrete class
- + @BeforeEach
- + protected void setup() {
- + EntityBuilder entityBuilderMock = mock(EntityBuilder.class);
- + jdaImplMock = mock(JDAImpl.class);
- + SelfUser selfUser = mock(SelfUserImpl.class);
- + UserImpl user = Mockito.spy(new UserImpl(userId, jdaImplMock));
- + privateChannel = Mockito.spy(new PrivateChannelImpl(userId, user));
- + MessageAction mockMessageAction = Mockito.mock(MessageActionImpl.class);
- +
- + when(entityBuilderMock.createUser(any())).thenReturn(user);
- + when(selfUser.getApplicationId()).thenReturn(String.valueOf(applicationId));
- + when(selfUser.getApplicationIdLong()).thenReturn(applicationId);
- + doReturn(selfUser).when(jdaImplMock).getSelfUser();
- + when(jdaImplMock.getPrivateChannelById(anyLong())).thenReturn(privateChannel);
- + when(jdaImplMock.getGatewayPool()).thenReturn(new ScheduledThreadPoolExecutor(4));
- + when(jdaImplMock.getEntityBuilder()).thenReturn(entityBuilderMock);
- + when(jdaImplMock.getSessionController()).thenReturn(new ConcurrentSessionController());
- + doReturn(new Requester(jdaImplMock, new AuthorizationConfig("TOKEN"))).when(jdaImplMock)
- + .getRequester();
- + doReturn(mockMessageAction).when(privateChannel).sendMessage(anyString());
- +
- + }
- +
- + protected SlashCommandEvent createSlashCommand(@Nonnull String command) {
- + DataObject dataObject = DataObject.fromJson("""
- + {
- + "id": 2,
- + "token": "asd",
- + "channel_id": 2,
- + "user": {
- + "id": 2
- + },
- + "type": 2,
- + "data": {
- + "id": 2,
- + "name": "%s"
- + }
- + }""".formatted(command));
- +
- + SlashCommandEvent slashCommandEvent = new SlashCommandEvent(jdaImplMock, 0,
- + new CommandInteractionImpl(jdaImplMock, dataObject));
- +
- + slashCommandEvent = Mockito.spy(slashCommandEvent);
- +
- + ReplyActionImpl replyActionImplMock = mock(ReplyActionImpl.class);
- +
- + doReturn(replyActionImplMock).when(slashCommandEvent).reply(anyString());
- +
- + return slashCommandEvent;
- + }
- +}
- diff --git a/application/src/test/java/org/togetherjava/tjbot/command/DatabaseCommandTest.java b/application/src/test/java/org/togetherjava/tjbot/command/DatabaseCommandTest.java
- new file mode 100644
- index 0000000..5a8171b
- --- /dev/null
- +++ b/application/src/test/java/org/togetherjava/tjbot/command/DatabaseCommandTest.java
- @@ -0,0 +1,144 @@
- +package org.togetherjava.tjbot.command;
- +
- +import net.dv8tion.jda.api.entities.ChannelType;
- +import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
- +import org.junit.jupiter.api.BeforeEach;
- +import org.junit.jupiter.api.DisplayName;
- +import org.junit.jupiter.api.Test;
- +import org.togetherjava.tjbot.AbstractJdaMock;
- +import org.togetherjava.tjbot.commands.Command;
- +import org.togetherjava.tjbot.commands.generic.DatabaseGetCommand;
- +import org.togetherjava.tjbot.commands.generic.DatabasePutCommand;
- +import org.togetherjava.tjbot.db.Database;
- +import org.togetherjava.tjbot.db.generated.tables.Storage;
- +import org.togetherjava.tjbot.db.generated.tables.records.StorageRecord;
- +
- +import java.sql.SQLException;
- +
- +import static org.mockito.Mockito.atLeastOnce;
- +import static org.mockito.Mockito.times;
- +import static org.mockito.Mockito.verify;
- +import static org.mockito.Mockito.when;
- +
- +class DatabaseCommandTest extends AbstractJdaMock {
- +
- + private Database database;
- + private SlashCommandEvent dbGetCommand;
- + private SlashCommandEvent dbPutCommand;
- +
- + public DatabaseCommandTest() {
- + super(2, 2);
- + }
- +
- + @BeforeEach
- + void setupDatabase() throws SQLException {
- + super.setup();
- + database = new Database("jdbc:sqlite:");
- +
- + // TODO - Remover this. We should use the flyway script, but I don't know a thing about
- + // using it with Gradle
- + database.writeTransaction(ctx -> {
- + ctx.ddl(Storage.STORAGE).executeBatch();
- + });
- +
- + dbGetCommand = createSlashCommand("dbget ditto");
- + dbPutCommand = createSlashCommand("dbput ditto evolved");
- +
- + when(dbGetCommand.getChannelType()).thenReturn(ChannelType.TEXT);
- + when(dbPutCommand.getChannelType()).thenReturn(ChannelType.TEXT);
- + }
- +
- + @DisplayName("""
- + Given an existing Database.
- + When a user retrieves a non-existing command.
- + Then an invalid message is returned
- + """)
- + @Test
- + void testGetCommand() {
- +
- + Command command = new DatabaseGetCommand(database);
- +
- + command.onSlashCommand(dbGetCommand);
- +
- + verify(dbGetCommand, times(1)).reply("Nothing found for the key 'ditto'");
- + }
- +
- + @DisplayName("""
- + Given an existing Database with commands present
- + When a user retrieves a command.
- + Then the correct response is returned
- + """)
- + @Test
- + void testGetWrongCommand() {
- +
- + database.writeTransaction(ctx -> {
- + StorageRecord storageRecord =
- + ctx.newRecord(Storage.STORAGE).setKey("ditto").setValue("evolution");
- + if (storageRecord.update() == 0) {
- + storageRecord.insert();
- + }
- + });
- +
- + Command command = new DatabaseGetCommand(database);
- +
- + command.onSlashCommand(dbGetCommand);
- +
- + verify(dbGetCommand, times(1)).reply("Saved message: evolution");
- + }
- +
- + @DisplayName("""
- + Given an existing Database with commands present
- + When a user updates a command.
- + Then the correct response is returned and the command is updated
- + """)
- + @Test
- + void testUpdateCommand() {
- + SlashCommandEvent failedDbGetCommand = createSlashCommand("dbget pikachu");
- + when(failedDbGetCommand.getChannelType()).thenReturn(ChannelType.TEXT);
- + Command getCommand = new DatabaseGetCommand(database);
- + Command putCommand = new DatabasePutCommand(database);
- +
- + putCommand.onSlashCommand(dbPutCommand);
- + getCommand.onSlashCommand(failedDbGetCommand);
- + getCommand.onSlashCommand(dbGetCommand);
- +
- + verify(dbPutCommand, times(1)).reply("Saved under 'ditto'.");
- + verify(failedDbGetCommand, times(1)).reply("Nothing found for the key 'pikachu'");
- + verify(dbGetCommand, times(1)).reply("Saved message: evolved");
- + }
- +
- + @DisplayName("""
- + Given an existing Database with commands present
- + When a user inserts invalid messages
- + Then the correct responses are returned
- + """)
- + @Test
- + void testErrorMessages() {
- + SlashCommandEvent errorCommand = createSlashCommand("dbget");
- + when(errorCommand.getChannelType()).thenReturn(ChannelType.TEXT);
- + Command command = new DatabaseGetCommand(database);
- +
- + command.onSlashCommand(errorCommand);
- +
- + verify(errorCommand, atLeastOnce())
- + .reply("Sorry, your message was in the wrong format, try '/dbget key'");
- + }
- +
- + @DisplayName("""
- + Given an invalid Database
- + When a user inserts messages
- + Then the correct responses are returned
- + """)
- + @Test
- + void testDatabaseErrorMessages() throws SQLException {
- + Database database = new Database("jdbc:sqlite:");
- + Command getCommand = new DatabaseGetCommand(database);
- + Command putCommand = new DatabasePutCommand(database);
- +
- + getCommand.onSlashCommand(dbGetCommand);
- + putCommand.onSlashCommand(dbPutCommand);
- +
- + verify(dbGetCommand, times(1)).reply("Sorry, something went wrong.");
- + verify(dbPutCommand, times(1)).reply("Sorry, something went wrong.");
- + }
- +}
- diff --git a/application/src/test/java/org/togetherjava/tjbot/command/PingCommandTest.java b/application/src/test/java/org/togetherjava/tjbot/command/PingCommandTest.java
- new file mode 100644
- index 0000000..c6ff9ac
- --- /dev/null
- +++ b/application/src/test/java/org/togetherjava/tjbot/command/PingCommandTest.java
- @@ -0,0 +1,38 @@
- +package org.togetherjava.tjbot.command;
- +
- +import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
- +import org.junit.jupiter.api.DisplayName;
- +import org.junit.jupiter.api.Test;
- +import org.togetherjava.tjbot.AbstractJdaMock;
- +import org.togetherjava.tjbot.commands.Command;
- +import org.togetherjava.tjbot.commands.generic.PingCommand;
- +
- +import static org.mockito.Mockito.anyString;
- +import static org.mockito.Mockito.atLeastOnce;
- +import static org.mockito.Mockito.times;
- +import static org.mockito.Mockito.verify;
- +
- +class PingCommandTest extends AbstractJdaMock {
- +
- + public PingCommandTest() {
- + super(2, 2);
- + }
- +
- + @DisplayName("""
- + Given an existing Ping Command implementation
- + When a command is fired that uses the ping command
- + Then a pong message is returned
- + """)
- + @Test
- + void testPingCommand() {
- + Command command = new PingCommand();
- +
- + SlashCommandEvent slashCommandEvent = createSlashCommand("ping");
- +
- + command.onSlashCommand(slashCommandEvent);
- +
- + // Assert and validate that our mock private channel calls the sendMessage event exactly
- + // once.
- + verify(slashCommandEvent, atLeastOnce()).reply("Pong!");
- + }
- +}
- --
- 2.23.0.windows.1
Advertisement
Add Comment
Please, Sign In to add comment