Есть ли способ легально разыграть ложный объект Mockito? - PullRequest
0 голосов
/ 26 марта 2020

Я написал пару классов тестовых примеров для моего маленького бота Discord в Java 11, JUnit Jupiter 5.6.0, Mockito 3.3.3 и Java Discord API 4.1.1_122.

I Я понял, что в моих тестовых примерах было многократное повторение поведения, в том числе объявление одинаковых макетов, используемых для той же цели, и повторение given([method call]).willReturn([object]); в моем методе запуска @BeforeEach. Я хотел разделить повторяющееся поведение на базовые классы, чтобы организовать себя, но я застрял. Все мои тестовые классы тестируют какой-то обработчик событий в Java Discord API Framework, поэтому я создал класс верхнего уровня с именем GenericEventTest:

public abstract class GenericEventTest {
    @Mock
    protected GenericEvent eventMock;

    @Mock
    protected JDA jdaMock;

    protected GenericEventTest() {
        MockitoAnnotations.initMocks(this);

        given(   eventMock.getJDA()   )
                .willReturn(jdaMock);
    }
}

Я хотел реализовать макет высокого уровня чтобы событие полиморфно вписалось в мои тестовые классы, поместите указанную команду given() в принадлежащий ему класс, потому что все мои тесты повторяют эту же строку. Затем я понял, что все мои тесты тестировали какое-то событие, связанное с сообщениями в Discord. Поэтому я расширил GenericEvent и сделал GuildMessageEventTest:

public abstract class GuildMessageEventTest extends GenericEventTest {
    @Mock
    protected GenericGuildMessageEvent eventMock;

    @Mock
    protected TextChannel eventChannelMock;

    @Mock
    protected MessageAction messageActionMock;

    protected GuildMessageEventTest() {
        super();

        MockitoAnnotations.initMocks(this);

        given(   eventMock.getChannel()   )
                .willReturn(eventChannelMock);

        given(   eventChannelMock.sendMessage(anyString())   )
                .willReturn(messageActionMock);
    }
}

Моя идея состоит в том, чтобы реализовать следующий уровень событий в этом классе, GenericGuildMessageEvent, к которому будут применены те же правила given() из GenericEvent, а затем добавьте соответствующие given() правила в этом классе. Но я считаю, что нашел свою проблему.

Когда я объявляю @Mock protected GenericGuildMessageEvent eventMock;, я слежу GenericEvent eventMock от GenericEventTest. Итак, я объявляю экземпляр GenericGuildMessageEvent, но я не сохраняю given() правил, которые были прикреплены к макету в GenericEventTest. Выполнение чего-то вроде @Mock protected GenericGuildMessageEvent eventMock = (GenericGuildMessageEvent) super.eventMock; не будет работать, потому что объекты, помеченные @Mock, не могут быть законно преобразованы таким образом.

Мой вопрос заключается в следующем: как я могу законным образом преобразовать свой экземпляр GenericEvent в GenericGuildMessageEvent, когда Mockito скопировал правила given(), прикрепленные к экземпляру GenericEvent в суперклассе?

1 Ответ

1 голос
/ 29 марта 2020

Объявите метод abstract GenericEvent getEventMock(); в вашем GenericEventTest и попросите GuildMessageEventTest его реализовать. Затем переместите поле экземпляра protected GenericEvent eventMock из базового класса в подкласс. Используйте getEventMock() для доступа к макету в базовом классе. Обратите внимание, что MockitoAnnotations.initMocks(this); не требуется снова в вашем подклассе. Это перезапишет поддельное поведение вашего базового класса.

// GenericEventTest
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import static org.mockito.BDDMockito.given;

public abstract class GenericEventTest {

    protected GenericEventTest() {
        MockitoAnnotations.initMocks(this);

        given(getEventMock().getJDA()).willReturn("jdaMock");
    }

    abstract GenericEvent getEventMock();
}

// GuildMessageEventTest
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import static org.mockito.BDDMockito.given;

public abstract class GuildMessageEventTest extends GenericEventTest {
    @Mock
    protected GenericGuildMessageEvent eventMock;

    @Mock
    protected GenericGuildMessageEvent myMock;

    @Override
    public GenericGuildMessageEvent getEventMock() {
        return eventMock;
    }

    protected GuildMessageEventTest() {
        super();

//        MockitoAnnotations.initMocks(this);

        given(eventMock.getChannel())
                .willReturn("eventChannelMock");

    }
}

//The Test
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

public class ActualMessageTest extends GuildMessageEventTest {

    @org.junit.jupiter.api.Test
    public void testX() {
        assertEquals("eventChannelMock", eventMock.getChannel());
        assertEquals("jdaMock", eventMock.getJDA());
        assertNotNull(myMock);
    }

}
...