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 Seasons.java
porque quiero burlarme de la RainOnTrees
clase. ¿Cómo puedo hacer esto con Mockito?
Respuestas:
Es posible burlarse de clases / métodos finales / estáticos solo con Mockito v2.
agregue esto en su archivo gradle:
Esto no es posible con Mockito v1, de las preguntas frecuentes de Mockito :
fuente
¡Mockito 2 ahora admite clases y métodos finales !
Pero por ahora esa es una característica de "incubación". Se requieren algunos pasos para activarlo que se describen en Novedades de Mockito 2 :
fuente
org.mockito.plugins.MockMaker
archivo en la carpeta correcta.No puedes burlarte de una clase final con Mockito, ya que no puedes hacerlo solo.
Lo que hago es crear una clase no final para ajustar la clase final y usarla como delegado. Un ejemplo de esto es la
TwitterFactory
clase, y esta es mi clase imitable:La desventaja es que hay mucho código repetitivo; La ventaja es que puede agregar algunos métodos que pueden estar relacionados con su negocio de aplicaciones (como el getInstance que está tomando un usuario en lugar de un AccessToken, en el caso anterior).
En su caso, crearía una
RainOnTrees
clase no final que delegue a la clase final. O, si puede hacerlo no final, sería mejor.fuente
@Delegate
para manejar una gran cantidad de repeticiones.agregue esto en su archivo gradle:
esta es una configuración para hacer que mockito funcione con las clases finales
fuente
org.mockito.exceptions.base.MockitoInitializationException: Could not initialize inline Byte Buddy mock maker. (This mock maker is not supported on Android.)
Utiliza Powermock. Este enlace muestra cómo hacerlo: https://github.com/jayway/powermock/wiki/MockFinal
fuente
Powermock
para burlarme de las clases finales y los métodos estáticos para aumentar mi cobertura que se verificó oficialmenteSonarqube
. La cobertura fue del 0% desde SonarQube, por cualquier razón no reconoce las clases que usan Powermock en cualquier lugar dentro de ella. A mi equipo y a mí nos llevó bastante tiempo darme cuenta de ello a través de algún hilo en línea. Esa es solo una de las razones para tener cuidado con Powermock y probablemente no lo use.Solo para seguir. Agregue esta línea a su archivo gradle:
He probado varias versiones de mockito-core y mockito-all. Ninguno de los dos trabaja.
fuente
Supongo que lo hiciste
final
porque quieres evitar que se extiendan otras clasesRainOnTrees
. Como sugiere Java Efectivo (ítem 15), hay otra forma de mantener una clase cerca para la extensión sin hacerlofinal
:Eliminar la
final
palabra clave;Haz su constructor
private
. Ninguna clase podrá extenderlo porque no podrá llamar alsuper
constructor;Cree un método de fábrica estático para crear instancias de su clase.
Al usar esta estrategia, podrá usar Mockito y mantener su clase cerrada por extensión con un pequeño código repetitivo.
fuente
Yo tuve el mismo problema. Como la clase que estaba tratando de burlar era una clase simple, simplemente creé una instancia y la devolví.
fuente
Prueba esto:
Funcionó para mi. "SomeMockableType.class" es la clase principal de lo que quiere burlarse o espiar, y someInstanceThatIsNotMockableOrSpyable es la clase real que desea burlarse o espiar.
Para más detalles mira aquí
fuente
Otra solución alternativa, que puede aplicarse en algunos casos, es crear una interfaz implementada por esa clase final, cambiar el código para usar la interfaz en lugar de la clase concreta y luego burlarse de la interfaz. Esto le permite separar el contrato (interfaz) de la implementación (clase final). Por supuesto, si lo que quiere es realmente unirse a la clase final, esto no se aplicará.
fuente
En realidad, hay una forma, que uso para espiar. Funcionaría para usted solo si se cumplen dos condiciones previas:
Por favor, recuerde el ítem 16 de Effective Java . Puede crear un contenedor (no final) y reenviar todas las llamadas a la instancia de la clase final:
Ahora no solo puedes burlarte de tu clase final sino también espiarla:
fuente
En Mockito 3 y más, tengo el mismo problema y lo solucioné desde este enlace
Simulacros de clases y métodos finales con Mockito de la siguiente manera
fuente
Ahorro de tiempo para las personas que enfrentan el mismo problema (Mockito + Final Class) en Android + Kotlin. Como en Kotlin, las clases son finales por defecto. Encontré una solución en una de las muestras de Google Android con el componente Arquitectura. Solución elegida desde aquí: https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample
Crea las siguientes anotaciones:
Modifica tu archivo gradle. Tomemos un ejemplo desde aquí: https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/build.gradle
Ahora puede anotar cualquier clase para abrirla para la prueba:
fuente
Esto se puede hacer si está utilizando Mockito2, con la nueva función de incubación que admite la burla de las clases y métodos finales.
Puntos clave a tener en cuenta:
1. Cree un archivo simple con el nombre "org.mockito.plugins.MockMaker" y colóquelo en una carpeta llamada "mockito-extensiones". Esta carpeta debe estar disponible en el classpath.
2. El contenido del archivo creado anteriormente debe ser una sola línea como se indica a continuación:
simulacro-maker-inline
Los dos pasos anteriores son necesarios para activar el mecanismo de extensión mockito y utilizar esta función de suscripción.
Las clases de muestra son las siguientes: -
FinalClass.java
}
Foo.java
}
FooTest.java
}
Espero eso ayude.
Artículo completo presente aquí burlándose de lo inamovible .
fuente
Sí, el mismo problema aquí, no podemos burlarnos de una clase final con Mockito. Para ser exactos, Mockito no puede burlarse / espiar lo siguiente:
Pero usar una clase de envoltura me parece un gran precio a pagar, así que obtenga PowerMockito en su lugar.
fuente
Creo que necesitas pensar más en principio. En cambio, tu clase final usa su interfaz y su simulacro de interfaz.
Para esto:
añadir
y burlarse de su interfaz:
fuente
Por favor mira a JMockit . Tiene una amplia documentación con muchos ejemplos. Aquí tiene una solución de ejemplo de su problema (para simplificar, he agregado un constructor
Seasons
para inyectar unaRainOnTrees
instancia simulada ):fuente
Las soluciones proporcionadas por RC y Luigi R. Viggiano juntos es posiblemente la mejor idea.
Aunque Mockito no puede , por diseño, simular clases finales, el enfoque de delegación es posible . Esto tiene sus ventajas:
En su caso de prueba, reenvía deliberadamente las llamadas al sistema bajo prueba. Por lo tanto, por diseño, su decoración no hace nada.
Por lo tanto, su prueba también puede demostrar que el usuario solo puede decorar la API en lugar de extenderla.
En una nota más subjetiva: prefiero mantener los marcos al mínimo, por eso JUnit y Mockito suelen ser suficientes para mí. De hecho, restringir este camino a veces me obliga a refactorizar para siempre.
fuente
Si intenta ejecutar la prueba unitaria en la carpeta de prueba , la solución principal está bien. Solo síguelo añadiendo una extensión.
Pero si desea ejecutarlo con una clase relacionada con Android como contexto o actividad que se encuentra en la carpeta androidtest , la respuesta es para usted.
fuente
Agregue estas dependencias para ejecutar mockito con éxito:
testImplementation 'org.mockito: mockito-core: 2.24.5'
testImplementation "org.mockito: mockito-inline: 2.24.5"
fuente
Como han dicho otros, esto no funcionará con Mockito. Sugeriría usar la reflexión para establecer los campos específicos en el objeto que está usando el código bajo prueba. Si te encuentras haciendo esto mucho, puedes incluir esta funcionalidad en una biblioteca.
Por otro lado, si eres el único que marca las clases finales, deja de hacerlo. Me encontré con esta pregunta porque estoy trabajando con una API donde todo se marcó como final para evitar mi legítima necesidad de extensión (burla), y deseo que el desarrollador no haya asumido que nunca necesitaría extender la clase.
fuente
final
debería ser el valor predeterminado.Para nosotros, fue porque excluimos mockito-inline de koin-test. Un módulo de Gradle realmente necesitaba esto y por razón solo falló en las versiones de lanzamiento (las versiones de depuración en el IDE funcionaron) :-P
fuente
Para la clase final, agregue a continuación para simular y llamar estática o no estática.
1- agregue esto en el nivel de clase @SuppressStatucInitializationFor (value = {class name with package})
2- PowerMockito.mockStatic (classname.class) se burlará de la clase
3- y luego usará su instrucción when para devolver el objeto simulado cuando llame al método de esta clase.
Disfrutar
fuente
No intenté final, pero en privado, usando la reflexión, elimine el modificador funcionó He comprobado más, no funciona para final.
fuente