Mockito y como cocinarlo

Sobre el artículo


Aquí hay otra guía de Mockito. En él, por un lado, traté de describir la funcionalidad de esta biblioteca para que un lector que no esté familiarizado con ella inmediatamente tenga la oportunidad de usarla por completo, y no solo una idea general. Por otro lado, quería hacerlo lo suficientemente compacto y estructurado para poder leerlo rápidamente en su totalidad y encontrar algo en él una vez leído, pero olvidado. En general, este artículo, que sería útil para mí, cuando acabo de encontrar esta biblioteca y realmente no entiendo cómo funciona.


Supongo que puede ser útil para mí ahora, a veces olvido algo de esto, y es más conveniente recordar el material no de acuerdo con la documentación oficial o los artículos de otras personas, sino de acuerdo con el mío, digamos, sinopsis. Al mismo tiempo, traté de construir el texto para que fuera conveniente principalmente para conocer a Mockito desde cero, y en algunos lugares analizo en detalle cosas aparentemente obvias, no todas las cuales me fueron obvias desde el principio.


Contenido:


  1. Mockito: qué es y por qué es necesario
  2. Entorno, versiones y animal experimental.
  3. burlarse y espiar
  4. Manejo de comportamiento
    1. Establecer condiciones de llamada
    2. Establecer resultados de llamadas
  5. Método de seguimiento de llamadas
  6. Objetos simulados como valores de campo y anotaciones simuladas
  7. Comportamiento de reversión a sesiones predeterminadas y Mockito
  8. Que mas

Mockito: qué es y por qué es necesario


En resumen, Mockito es un marco de código auxiliar.


Como sabe, cuando se prueba el código (principalmente pruebas unitarias, pero no solo), el elemento bajo prueba a menudo necesita proporcionar instancias de clases que debería usar cuando funciona. Sin embargo, a menudo no tienen que ser completamente funcionales; por el contrario, deben comportarse de una manera estrictamente definida, de modo que su comportamiento sea simple y completamente predecible. Se llaman trozos. Para obtenerlos, puede crear implementaciones de prueba alternativas de interfaces, heredar las clases necesarias con la redefinición de la funcionalidad, etc., pero todo esto es bastante inconveniente, redundante y lleno de errores. Una solución más conveniente en todos los sentidos son los marcos especializados para crear stubs. Uno de ellos (y quizás el más famoso por Java) es Mockito.


Mockito le permite crear con una sola línea de código el llamado simulacro (algo así como la base para el código auxiliar deseado) de cualquier clase. Para tal simulacro, inmediatamente después de la creación, es característico un cierto comportamiento predeterminado (todos los métodos devuelven valores previamente conocidos, generalmente esto es null o 0 ). Puede redefinir este comportamiento de la manera que desee, controlarlo con el grado correcto de detalle, etc. Como resultado, el simulacro se convierte en un trozo con las propiedades requeridas. A continuación discutiré en detalle cómo hacer esto.


Observo que también se puede crear simulacro para esas clases, cuya nueva instancia en realidad no se puede crear, en particular, clases con constructores exclusivamente privados como clases singleton y utilidades, y con una configuración mínima del marco y enumeraciones.


Entorno, versiones y animal experimental.


Al escribir este artículo, usé:


  • Mockito: 'org.mockito: mockito-core: 2.24.0' (última versión estable al momento de escribir)
  • TestNG: 'org.testng: testng: 6.14.3' como marco de prueba
  • AssertJ: 'org.assertj: afirj-core: 3.11.1' como herramienta de validación
  • Lombok: 'org.projectlombok: lombok: 1.18.6' (solo por conveniencia)
  • Java 8

Para mis experimentos inhumanos, escribí esta interfaz de un servicio que proporciona acceso a ciertos datos.


 public interface DataService { void saveData(List<String> dataToSave); String getDataById(String id); String getDataById(String id, Supplier<String> calculateIfAbsent); List<String> getData(); List<String> getDataListByIds(List<String> idList); List<String> getDataByRequest(DataSearchRequest request); } 

Y este código (dejándolo en orden) de la clase de solicitud pasó al último de los métodos de interfaz.


 @AllArgsConstructor @Getter class DataSearchRequest { String id; Date updatedBefore; int length; } 

Las unidades de datos se identifican por ID y tienen algunas características más, pero directamente en la forma en que son devueltas por el servicio, son cadenas y no algunos objetos más complejos. No me pierdo nada importante, y los ejemplos son más simples y claros.


Notaré de inmediato: en los ejemplos a continuación, llamo directamente a los métodos anulados de mis objetos simulados para mayor claridad, pero con pruebas reales, ¡la idea no es para nada! En esta prueba, siempre haría lo siguiente:


  • configuré el simulacro de mi servicio según sea necesario;
  • lo pasó (muy probablemente, a través del constructor) a una instancia de otra clase que lo usa (supongamos que contiene algún tipo de lógica de negocios usando los datos proporcionados por el DataService ), que en realidad probaría;
  • habilitó la funcionalidad de la clase probada y controló los resultados;
  • si es necesario, controlaría el número y el orden de las llamadas a los métodos de mi simulacro, que la clase probada debería haber llamado como resultado de la acción anterior.

burlarse y espiar


La clase central de Mockito, a través de la cual se supone que debe acceder a la mayor parte de la funcionalidad, es, de hecho, una clase llamada Mockito (también existe la clase BDDMockito que proporciona aproximadamente las mismas posibilidades en una forma más adecuada para BDD , pero aquí no me detendré en ella) . El acceso a la funcionalidad se implementa a través de sus métodos estáticos.


Para crear un simulacro de la clase DataService , solo tengo que hacer lo siguiente:


 DataService dataServiceMock = Mockito.mock(DataService.class); 

Hecho: obtuve una instancia de la clase que necesito. Será aceptado por cualquier método o constructor que requiera un parámetro de este tipo (por ejemplo, el constructor de la clase que quiero probar). Incluso si una verificación de adicción lo espera más tarde, lo pasará: no solo la instanceof DataService devolverá true , sino también dataServiceMock.getClass() , es decir, DataService.class . De alguna manera formal, distinguir programáticamente un objeto simulado de uno ordinario resulta ser una tarea bastante difícil, lo cual es lógico: después de todo, el primero está destinado a ser indistinguible del segundo. Sin embargo, Mockito tiene una herramienta para esto: el método Mockito.mockingDetails . Al pasarle un objeto arbitrario, obtengo un objeto de la clase MockingDetails . Contiene información sobre lo que este objeto representa desde el punto de vista de Mockito: si es simulado, espía (ver más abajo), cómo se usó, cómo se creó, etc.


De particular interés es la situación cuando trato de crear un simulacro para la clase final o una instancia simulada de enumeración o para anular el comportamiento del método final. En este caso, con el comportamiento predeterminado de Mockito, el código anterior se niega a funcionar, citando precisamente esta circunstancia. Sin embargo, esto se puede cambiar: simplemente cree en el proyecto (con el dispositivo estándar del árbol de directorios del proyecto) el archivo test/resources/mockito-extensions/org.mockito.plugins.MockMaker e ingrese la línea en él:


 mock-maker-inline 

Después de eso, puede imitar las clases y enumeraciones finales de la manera habitual, y también anular los métodos finales.


El simulacro que obtuve en la acción es lo menos funcional posible: ni un solo método tendrá ningún efecto en nada, y el valor devuelto será null para los tipos de objeto y 0 para los primitivos. Tenga en cuenta: si el método devuelve una colección, el simulacro predeterminado no devolverá null , sino instancias de colección vacías. Por ejemplo, para List esto resultará en un LinkedList vacío LinkedList independientemente de lo que el método real debería haber devuelto. Pero como los valores de los arrays, primitivos u objetos, obtengo un null . El comportamiento predeterminado (y no solo él) se puede cambiar utilizando la funcionalidad de la clase MockSettings , pero esto rara vez es necesario.


De una forma u otra, en la mayoría de los casos no necesitaré el comportamiento predeterminado, y en la siguiente sección analizaré en detalle cómo configurar lo que se requiere.


Sin embargo, ¿qué sucede si quiero usar un objeto de clase real con la funcionalidad disponible como un código auxiliar, redefiniendo la operación de solo una parte de sus métodos? Si estamos hablando de pruebas unitarias, tal necesidad generalmente (pero no siempre) indica que el proyecto no está bien con el diseño y, en principio, esto no se recomienda. Sin embargo, hay situaciones en que esto por alguna razón no se puede evitar. Para este caso, Mockito tiene el llamado espía, "espías". A diferencia de los simulacros, se pueden crear según la clase y el objeto terminado:


 DataService dataServiceSpy = Mockito.spy(DataService.class); // or DataService dataService = new DataService(); dataServiceSpy = Mockito.spy(dataService); 

Al crear un espía basado en una clase, si su tipo es una interfaz, se creará un objeto simulado regular, y si el tipo es una clase, Mockito intentará crear una instancia utilizando el constructor predeterminado (sin parámetros). Y solo si no existe tal constructor, se producirá un error y la prueba no funcionará.


El comportamiento predeterminado de los objetos espía es idéntico al comportamiento de una instancia de clase regular, sin embargo, me dan las mismas posibilidades que los objetos simulados: me permiten redefinir su comportamiento y monitorear su uso (consulte las siguientes secciones). Un punto importante: ¡el espía no es un envoltorio alrededor de la instancia en la que se creó! Por lo tanto, llamar al método espía no afectará el estado de la instancia original.


Manejo de comportamiento


Entonces, sobre cómo hacer burlarse o espiar para hacer lo que necesito. Además, siempre escribiré simplemente "simulacro" en todas partes; esto significará "simulacro o espía", a menos que se indique expresamente lo contrario.


En general, controlar el comportamiento de un objeto simulado se reduce a un concepto obvio: cuando se actuaba sobre un simulacro de esa manera (es decir, se llamaba a un método con tales argumentos), debería responder de tal y tal manera. Este concepto tiene dos implementaciones dentro de la clase Mockito: la principal, recomendada por los desarrolladores para su uso siempre que sea posible, y la alternativa, utilizada donde la principal no es adecuada.


La implementación principal se basa en el método Mockito.when . Este método toma como "parámetro" una llamada al método redefinido del objeto simulado (de esta forma, la acción detectada es fija) y devuelve un objeto de tipo OngoingStubbing , que permite llamar a uno de los métodos de la familia Mockito.then... (así es como se configura la reacción a este efecto). Todos juntos, en el caso más simple, se ve así:


 List<String> data = new ArrayList<>(); data.add("dataItem"); Mockito.when(dataService.getAllData()).thenReturn(data); 

Después de esta operación, al llamar al método getAllData() en el objeto getAllData() , obtengo el objeto especificado en la primera línea de la lista.


Aquí, la intuición familiar "orientada a objetos" puede dar algún tipo de mal funcionamiento, por lo que vale la pena detenerse en más detalle. Desde el punto de vista de la sintaxis de Java, el valor pasado when método when como parámetro es, por supuesto, el valor devuelto por el método reemplazado. Para simulacro, este es un valor vacío; para espía, este es el valor devuelto por el método del objeto real. Pero gracias a la magia que actúa "bajo el capó" de Mockito, el método when funcionará normalmente (y no se bloqueará cuando se inicie con un error) solo si la llamada al método mock-object está dentro de los corchetes después de when .


Una ideología similar a menudo funciona cuando se define el comportamiento de un simulacro en un Mockito: al llamar a un método (de un objeto simulado o clase del Mockito ), trato de no obtener el valor devuelto por él, pero de alguna manera influir en la posible llamada del método del objeto simulado con el que trabajo: especificar sus límites, establecer el resultado, establecer la observación de sus desafíos, etc. Parece un poco brumoso, lo admito, y en la primera colisión parece extraño, pero una vez que lo descubres, muy pronto comienzas a sentir que este enfoque es completamente natural en el contexto de trabajar con trozos.


Una implementación alternativa de vincular la condición y el resultado de la llamada son los métodos de la familia Mockito.do... Estos métodos le permiten establecer el comportamiento comenzando con el resultado de la llamada y devolver un objeto de la clase Stubber , con el que ya puede establecer la condición. El mismo enlace que el anterior realizado de esta manera se ve así:


 List<String> data = new ArrayList<>(); data.add("dataItem"); Mockito.doReturn(data).when(dataService).getData() 

¿Cuál es la diferencia, por qué vincularse a través de Mockito.when se considera preferible y cuando todavía tiene que usar los métodos de Mockito.do... ? Tenga en cuenta: en la primera implementación, al definir el comportamiento del método (en este caso, getAllData() ), la llamada a la versión que aún no se ha redefinido se realiza primero, y solo luego, en las entrañas del Mockito, se produce una anulación. En el segundo, no se produce una llamada de este tipo: el método Stubber.when pasa directamente al método Stubber.when , y un objeto del mismo tipo devuelto por este método pero de diferente naturaleza se llama con un método reemplazable. Esta diferencia determina todo. El enlace a través de Mockito.do... no controla en absoluto en la etapa de compilación qué método redefinible llamaré y si es compatible en tipo con el valor de retorno dado. Por lo tanto, generalmente Mockito.when preferible, no puede haber ningún error con esto. Pero puede haber casos en los que quiera evitar llamar a un método anulado: para un simulacro recién creado, tal llamada es bastante aceptable, pero si ya he redefinido este método o trato con un espía, puede ser indeseable, y lanzar una excepción no permitirá la redefinición necesaria. . Y aquí vinculante a través de Mockito.do... viene al Mockito.do...


Otra situación en la que no puede prescindir de los métodos Mockito.do... es anular el método que devuelve void : el parámetro Mockito.when pendiente Mockito.when no puede funcionar con dicho método. Mockito.doReturn , por supuesto, sin trabajo, pero hay Mockito.doThrow , Mockito.doAnswer y rara vez hay suficientes Mockito.doNothing .


A continuación, consideraré con un poco más de detalle cómo establecer las condiciones y los resultados de las llamadas. Solo consideraré la vinculación a través de Mockito.when . Mockito.when : una forma alternativa es casi completamente similar en el manejo.


Establecer condiciones de llamada


El ejemplo anterior se refiere a un método sin parámetros, y la condición de llamada asociada es una cosa posible: el hecho de la llamada. Tan pronto como aparecen los parámetros, la situación se vuelve más complicada. Como mínimo, para llamar a un método cuyo comportamiento estoy configurando, necesito pasarle algo. Pero otra cosa es más importante: puede resultar que no siempre quiero obtener la reacción dada, sino solo cuando la llamo con parámetros que cumplen ciertos requisitos. DataService tiene este método:


 String getDataItemById(String id) { // some code... } 

Si necesito establecer una respuesta a cualquier llamada a este método, independientemente de los argumentos, debo usar el método Mockito.any :


 Mockito.when(dataService.getDataItemById(any())) .thenReturn("dataItem"); 

Si necesito un simulacro para reaccionar solo a un cierto valor del argumento, puede usar este valor directamente o los métodos de Mockito.eq (si es una equivalencia) o Mockito.same (si se requiere una comparación de enlaces):


 Mockito.when(dataService.getDataItemById("idValue")) .thenReturn("dataItem"); // or Mockito.when(dataService.getDataItemById(Mockito.eq("idValue"))) .thenReturn("dataItem"); 

Y si quiero que el argumento cumpla con algunos requisitos, hay varios métodos estáticos especializados convenientes de la misma clase Mockito (por ejemplo, se puede verificar el contenido de las cadenas al principio o al final de una determinada secuencia de caracteres, coincidencia de patrones, etc.). También hay un método general Mockito.argThat (y sus análogos para tipos primitivos) que acepta la implementación de la interfaz funcional ArgumentMatcher:


 Mockito.when(dataService.getDataById( Mockito.argThat(arg -> arg == null || arg.length() > 5))) .thenReturn("dataItem"); 

Las clases ArgumentMatchers y AdditionalMatchers permiten trabajar con algunas implementaciones útiles de esta interfaz. Por ejemplo, AdditionalMatchers.or y AdditionalMatchers.and permiten combinar otros matchers (nota: ¡los métodos estáticos de estas clases no devuelven instancias de matchers, sino que solo acceden a ellos!)


Para el mismo método, puede establecer el comportamiento varias veces con diferentes requisitos para los argumentos, y todos los modelos de comportamiento definidos de esta manera actuarán simultáneamente. Por supuesto, en algunos casos, pueden cruzarse, por ejemplo, exigiré que devuelva un resultado cuando el valor int del parámetro sea menor que 5 y el otro cuando se reciba el valor par. En esta situación, el comportamiento que se especifica más adelante tiene prioridad. Por lo tanto, al definir patrones de comportamiento complejos, debe comenzar con los requisitos más débiles (en el límite - any() ) y solo luego pasar a los más específicos.


Cuando se trabaja con métodos con más de un argumento, los requisitos especificados se combinan de acuerdo con la lógica Y, es decir, para obtener el resultado dado, CADA uno de los argumentos debe cumplir con el requisito establecido. No encontré una manera de establecer una forma arbitraria de combinarlos, aunque tal vez exista.


Además, cuando se especifica el comportamiento de dicho método, no se pueden combinar los métodos estáticos de Mockito y la transferencia directa de valores. Use Mockito.eq o Mockito.same .


Establecer resultados de llamadas


Después de llamar al método de objeto simulado, el objeto debe responder a la llamada. Las principales consecuencias posibles son devolver el resultado y lanzar una excepción, y es precisamente en estas opciones que el kit de herramientas Mockito está diseñado principalmente.


En el caso más simple que se muestra arriba, la respuesta a la llamada es devolver un valor. Daré su código nuevamente:


 List<String> data = new ArrayList<>(); data.add("dataItem"); Mockito.when(dataService.getAllData()).thenReturn(data); 

Tenga en cuenta: solo puede devolver un objeto; no hay métodos separados para las primitivas. Por lo tanto, si el método devuelve un valor primitivo, en tal situación se producirá un / boxing. En la mayoría de los casos, esto no interfiere, pero si el compilador piensa lo contrario, tendrá que estar de acuerdo con él ... o soportar sus advertencias.


Lanzar excepciones no es más difícil:


 Mockito.when(dataService.getDataById("invalidId")) .thenThrow(new IllegalArgumentException()); 

Hay otra forma: puede crear un objeto de excepción y lanzarlo directamente, o puede proporcionar a Mockito solo una clase de excepción para que se cree automáticamente:


 Mockito.when(dataService.getDataById("invalidId")) .thenThrow(IllegalArgumentException.class); 

En ambos casos, la sintaxis le permite usar y verificar excepciones, sin embargo, Mockito no le permitirá ejecutar dicha prueba si el tipo de excepción no coincide con el método que quiero forzar a lanzar esta excepción.


Cuando se usa una clase como parámetro, los constructores (incluso sin parámetros), así como la inicialización de campo directa, se ignoran: el objeto se crea sin pasarlos (después de todo, ¡esto es Mockito!), De modo que todos los campos de la excepción lanzada serán null . Por lo tanto, si el contenido de la excepción es importante para usted (por ejemplo, algún campo de type que tenga un valor predeterminado), deberá abandonar este método y crear excepciones manualmente.


Estas opciones de reacción son adecuadas si, en respuesta a una llamada con condiciones dadas, siempre necesita devolver un cierto, siempre el mismo valor del resultado o siempre arrojar la misma excepción, y en la mayoría de los casos estas capacidades son suficientes. Pero, ¿qué pasa si se requiere más flexibilidad? Supongamos que mi método acepta una colección de valores y devuelve otra colección de valores asociados con el primero a uno (por ejemplo, obtener una colección de objetos de datos por el conjunto de sus ID), y quiero usar este objeto simulado repetidamente con diferentes conjuntos de entrada en la prueba datos, obteniendo cada vez el resultado correspondiente. Por supuesto, puede describir por separado la reacción a cada conjunto específico de parámetros, pero hay una solución más conveniente: el método Mockito.thenAnswer , también Mockito.then como Mockito.then . Acepta una implementación de la interfaz funcional Answer , cuyo único método es recibir un objeto de la clase InvocationOnMock . Desde este último puedo solicitar los parámetros de la llamada al método (uno por número o todos a la vez en forma de matriz) y actuar con ellos, como me plazca. Por ejemplo, puede obtener un valor correspondiente a cada uno de los elementos de mi colección, formar una nueva colección a partir de ellos y devolverlo (nota: el resultado deseado simplemente se devuelve, pero no se escribe en algún campo del objeto de parámetro, como es de esperar):


 Mockito.when(dataService.getDataByIds(Mockito.any())) .thenAnswer(invocation -> invocation .<List<String>>getArgument(0).stream() .map(id -> { switch (id) { case "a": return "dataItemA"; case "b": return "dataItemB"; default: return null; } }) .collect(Collectors.toList())); 

Ideológicamente, esto es algo así como escribir un modelo de un método real: obtener parámetros, procesar, devolver un resultado. - , - , , , mock- .


Answer , , — , AnswersWithDelay , ReturnsElementsOf . .


: InvocationOnMock — Object[] , generic-.


— thenCallRealMethod . . mock-, spy-. mock , , - null . spy thenCallRealMethod spy ; , - .


thenAnswer : InvocationOnMock callRealMethod() — , "" - .


OngoingStubbing OngoingStubbing , , , . , . thenReturn thenThrow , varargs. .


 Mockito.when(dataService.getDataById("a")) .thenReturn("valueA1", "valueA2") .thenThrow(IllegalArgumentException.class); 

"valueA1 , — "valueA2 ( ), ( ) IllegalArgumentException .



: (mock' ), . , : , , . verify .


, , :


 Mockito.verify(dataService).getDataById(Mockito.any()); 

, getDataById , , . , Mockito, when , , , mock-. , , , when , — mock', (. ).


:


 Mockito.verify(dataService, Mockito.times(1)) .getDataById(Mockito.any()); 

Mockito.times ; Mockito.never . Mockito.atLeast ( Mockito.atLeastOnce 1) Mockito.atMost , , Mockito.only , , mock- (. . ).


, Mockito , VerificationAfterDelay VerificationWithTimeout , Mockito.after Mockito.timeout . Por ejemplo:


 Mockito.verify(dataService, Mockito.after(1000).times(1)) .getDataById(Mockito.any()); 

, mock , , , . . after timeout , , , — , . , timeout — . VerificationWithTimeout never atMost : .


, Mockito.any() . , , — Mockito , , . Mock- , , , , :


 dataService.getDataById("a"); dataService.getDataById("b"); Mockito.verify(dataService, Mockito.times(2)).getDataById(Mockito.any()); Mockito.verify(dataService, Mockito.times(1)).getDataById("a"); Mockito.verify(dataService, Mockito.never()).getDataById("c"); dataService.getDataById("c"); Mockito.verify(dataService, Mockito.times(1)).getDataById("c"); Mockito.verifyNoMoreInteractions(dataService); 

verifyNoMoreInteractions ( verifyZeroInteractions ) — - ( verify ) mock- — . : varargs, , , !


, , , . , InOrder :


 InOrder inOrder = Mockito.inOrder(dataService); 

varargs; — mock- , InOrder . verify , Mockito.verify :


 inOrder.verify(dataService, times(2)).saveData(any()); inOrder.verify(dataService).getData(); 

, saveData , — getData . , InOrder , — .


, , — , . - , , — , , . ArgumentCaptor capture() . Por ejemplo:


 DataSearchRequest request = new DataSearchRequest("idValue", new Date(System.currentTimeMillis()), 50); dataService.getDataByRequest(request); ArgumentCaptor<DataSearchRequest> requestCaptor = ArgumentCaptor.forClass(DataSearchRequest.class); Mockito.verify(dataService, times(1)).getDataByRequest(requestCaptor.capture()); assertThat(requestCaptor.getAllValues()).hasSize(1); DataSearchRequest capturedArgument = requestCaptor.getValue(); assertThat(capturedArgument.getId()).isNotNull(); assertThat(capturedArgument.getId()).isEqualTo("idValue"); assertThat(capturedArgument.getUpdatedBefore()).isAfterYear(1970); assertThat(capturedArgument.getLength()).isBetween(0, 100); 

ArgumentCaptor , , ArgumentCaptor . getValue() , getAllValues() — . , , .


Mock- Mockito


, mock- , — @Mock - :


 MockitoAnnotations.initMocks(this); 

( , mock', )


spy @Spy — @Mock … spy , , ? , — spy .


@Captor ArgumentCaptor — , , .


@InjectMocks . - Mockito, . mock- , . , . - , null , - . ( ) dependency injection.


Mockito


, : mock (spy, argument captor...), , , . , mock' — , . JUnit , , TestNG — . , , mock' , , , . . , , — , .


, mock- . TestNG @BeforeMethod ( @AfterMethod ). mock' , , ( JUnit — @Before ).


, , — Mockito.reset Mockito.clearInvocations . varargs, mock'. , . : (, ) , / mock' , — . , mock' . . , , .


(, ) — MockitoAnnotations.initMocks(this); . "" , Mockito.


— Mockito. . mock- , ( mock' ). , MockitoSession , . TestNG:


 @Mock DataService dataService; MockitoSession session; @BeforeMethod public void beforeMethod() { session = Mockito.mockitoSession() .initMocks(this) .startMocking(); } @Test public void testMethod() { // some code using the dataService field } @AfterMethod public void afterMethod() { session.finishMocking(); } 

, — , "" (, ) , .


?


Mockito: mock spy-, . , . , , :


  • Mockito mock- MockSettings ( — , mock' - );
  • mock-, MockingDetails ;
  • BDDMockito Mockito ;
  • ( JUnit Mockito, ).

Mockito . javadoc' Mockito .


, , .

Source: https://habr.com/ru/post/444982/


All Articles