Cómo burlarse de una clase final con mockito
Tengo una clase final, algo como esto:
public final class RainOnTrees{
public void startRain(){
// some code here
}
}
Estoy usando esta clase en alguna otra clase como esta:
public class Seasons{
RainOnTrees rain = new RainOnTrees();
public void findSeasonAndRain(){
rain.startRain();
}
}
y en mi clase de prueba JUnit porque Seasons.java
quiero burlarme de la RainOnTrees
clase. ¿Cómo puedo hacer esto con Mockito?
Burlarse de clases/métodos finales/estáticos es posible solo con Mockito v2.
agregue esto en su archivo gradle:
testImplementation 'org.mockito:mockito-inline:2.13.0'
Esto no es posible con Mockito v1, de las preguntas frecuentes de Mockito :
¿Cuáles son las limitaciones de Mockito?
Necesita java 1.5+
No puedo burlarme de las clases finales.
...
¡Mockito 2 ahora admite clases y métodos finales!
Pero por ahora se trata de una característica en "incubación". Requiere algunos pasos para activarlo que se describen en Novedades de Mockito 2 :
La burla de las clases y métodos finales es una característica opcional en incubación . Utiliza una combinación de instrumentación del agente Java y subclases para permitir la burla de estos tipos. Como esto funciona de manera diferente a nuestro mecanismo actual y este tiene diferentes limitaciones y como queremos recopilar experiencia y comentarios de los usuarios, esta función tuvo que activarse explícitamente para que esté disponible; se puede hacer a través del mecanismo de extensión Mockito creando el archivo
src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
que contiene una sola línea:mock-maker-inline
Después de crear este archivo, Mockito usará automáticamente este nuevo motor y se puede hacer:
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());
En hitos posteriores, el equipo aportará una forma programática de utilizar esta función. Identificaremos y brindaremos soporte para todos los escenarios imposibles de burlar. ¡Estén atentos y díganos qué piensa de esta función!
agregue esto en su archivo de compilación:
- si usa gradle :
build.gradle
testImplementation 'org.mockito:mockito-inline:2.13.0'
- si usa maven :
pom.xml
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>2.13.0</version>
<scope>test</scope>
</dependency>
esta es una configuración para hacer que Mockito funcione con las clases finales.
Si se enfrentó a la dependencia Could not initialize inline Byte Buddy mock maker. (This mock maker is not supported on Android.)
Agregar el Byte Buddy a su build.gradle
archivo:
testImplementation 'net.bytebuddy:byte-buddy-agent:1.10.19'
src: https://mvnrepository.com/artifact/net.bytebuddy/byte-buddy
No puedes burlarte de una clase final con Mockito, ya que no puedes hacerlo tú solo.
Lo que hago es crear una clase no final para envolver la clase final y usarla como delegado. Un ejemplo de esto es TwitterFactory
la clase, y esta es mi clase simulada:
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();
}
}
La desventaja es que hay mucho código repetitivo; la ventaja es que puede agregar algunos métodos que puedan estar relacionados con el negocio de su aplicación (como getInstance, que toma un usuario en lugar de un accessToken, en el caso anterior).
En su caso, crearía una RainOnTrees
clase no final que delegaría a la clase final. O, si puede hacerlo no definitivo, sería mejor.
En Mockito 3 y más tengo el mismo problema y lo solucioné desde este enlace
Simule clases y métodos finales con Mockito de la siguiente manera
Antes de que Mockito pueda usarse para burlarse de clases y métodos finales, debe configurarse.
Necesitamos agregar un archivo de texto al directorio src/test/resources/mockito-extensions del proyecto llamado org.mockito.plugins.MockMaker y agregar una sola línea de texto:
mock-maker-inline
Mockito comprueba el directorio de extensiones en busca de archivos de configuración cuando está cargado. Este archivo permite burlarse de los métodos y clases finales.