Вопрос-ответ

How to mock a final class with mockito

Как создать окончательный класс с помощью mockito

У меня есть конечный класс, что-то вроде этого:

public final class RainOnTrees{

public void startRain(){

// some code here
}
}

Я использую этот класс в каком-то другом классе, подобном этому:

public class Seasons{

RainOnTrees rain = new RainOnTrees();

public void findSeasonAndRain(){

rain.startRain();

}
}

и в моем тестовом классе JUnit для Seasons.java я хочу смоделировать RainOnTrees класс. Как я могу это сделать с помощью Mockito?

Переведено автоматически
Ответ 1

Имитация конечных / статических классов / методов возможна только с Mockito v2.

добавьте это в свой файл gradle:

testImplementation 'org.mockito:mockito-inline:2.13.0'

Это невозможно с Mockito v1, из часто задаваемых вопросов по Mockito:


Каковы ограничения Mockito



  • Требуется java 1.5+


  • Невозможно смоделировать конечные классы



...


Ответ 2

Mockito 2 теперь поддерживает конечные классы и методы!

Но пока это "инкубационная" функция. Для ее активации требуется выполнить несколько шагов, которые описаны в Что нового в Mockito 2:


Смоделирование конечных классов и методов - это инкубирующая возможность выбора. В нем используется комбинация инструментария Java agent и подклассов, чтобы обеспечить возможность макетирования этих типов. Поскольку это работает иначе, чем наш текущий механизм, и у этого есть другие ограничения, и поскольку мы хотим собрать опыт и отзывы пользователей, эту функцию пришлось явно активировать, чтобы она была доступна ; это можно сделать с помощью механизма расширения mockito, создав файл, src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker содержащий одну строку:


mock-maker-inline

После того, как вы создали этот файл, Mockito автоматически будет использовать этот новый движок, и можно будет сделать :


 final class FinalClass {
final String finalMethod() { return "something"; }
}

FinalClass concrete = new FinalClass();

FinalClass mock = mock(FinalClass.class);
given(mock.finalMethod()).willReturn("not anymore");

assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());

На последующих этапах команда разработает программный способ использования этой функции. Мы определим и обеспечим поддержку для всех не поддающихся редактированию сценариев. Следите за обновлениями и, пожалуйста, сообщите нам, что вы думаете об этой функции!


Ответ 3

добавьте это в свой файл сборки:


  • при использовании gradle: build.gradle

testImplementation 'org.mockito:mockito-inline:2.13.0'

  • при использовании maven: pom.xml

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>2.13.0</version>
<scope>test</scope>
</dependency>

это конфигурация, позволяющая заставить mockito работать с конечными классами

Если вы столкнулись с Could not initialize inline Byte Buddy mock maker. (This mock maker is not supported on Android.) Добавьте в свой файл зависимость Byte Buddybuild.gradle:

testImplementation 'net.bytebuddy:byte-buddy-agent:1.10.19'

src: https://mvnrepository.com/artifact/net.bytebuddy/byte-buddy

Ответ 4

Вы не можете смоделировать конечный класс с помощью Mockito, так как вы не можете сделать это самостоятельно.

Что я делаю, так это создаю класс, не являющийся окончательным, чтобы обернуть конечный класс и использовать в качестве делегата. Примером этого является TwitterFactory class, и это мой класс-макет:

public class TwitterFactory {

private final twitter4j.TwitterFactory factory;

public TwitterFactory() {
factory = new twitter4j.TwitterFactory();
}

public Twitter getInstance(User user) {
return factory.getInstance(accessToken(user));
}

private AccessToken accessToken(User user) {
return new AccessToken(user.getAccessToken(), user.getAccessTokenSecret());
}

public Twitter getInstance() {
return factory.getInstance();
}
}

Недостатком является то, что существует много шаблонного кода; преимущество в том, что вы можете добавить некоторые методы, которые могут относиться к бизнесу вашего приложения (например, getInstance, который принимает пользователя вместо accessToken, в приведенном выше случае).

В вашем случае я бы создал не окончательный RainOnTrees класс, который делегирует конечному классу. Или, если вы можете сделать его не окончательным, это было бы лучше.

java junit