Cómo resolver la excepción de Stubbing innecesario

101

Mi código es el siguiente,

@RunWith(MockitoJUnitRunner.class)
public class MyClass {

    private static final String code ="Test";

    @Mock
     private MyClassDAO dao;

    @InjectMocks
     private MyClassService Service = new MyClassServiceImpl();

    @Test
     public void testDoSearch() throws Exception {
         final String METHOD_NAME = logger.getName().concat(".testDoSearchEcRcfInspections()");
         CriteriaDTO dto = new CriteriaDTO();
         dto.setCode(code);
         inspectionService.searchEcRcfInspections(dto);
         List<SearchCriteriaDTO> summaryList = new ArrayList<SearchCriteriaDTO>();
         inspectionsSummaryList.add(dto);
         when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);//got error in this line
         verify(dao).doSearchInspections(dto);

      }
}

Me estoy poniendo por debajo de la excepción

org.mockito.exceptions.misusing.UnnecessaryStubbingException: 
Unnecessary stubbings detected in test class: Test
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
  1. -> at service.Test.testDoSearch(Test.java:72)
Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class.
  at org.mockito.internal.exceptions.Reporter.formatUnncessaryStubbingException(Reporter.java:838)
  at org.mockito.internal.junit.UnnecessaryStubbingsReporter.validateUnusedStubs(UnnecessaryStubbingsReporter.java:34)
  at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:49)
  at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:103)
  at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
  at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

Por favor ayúdame a resolver

VHS
fuente

Respuestas:

120

Reemplazar @RunWith(MockitoJUnitRunner.class)con @RunWith(MockitoJUnitRunner.Silent.class).

Sumit
fuente
44
Bienvenidos. Valdría la pena actualizar su respuesta para explicar por qué OP deberían reemplazar dicho código. Esto les ayudará a ellos y a los futuros visitantes a comprender.
Bugs
5
Por cierto, es @RunWith(MockitoJUnitRunner.Silent.class)y no SILENCIOSO
fgysin reintegra a Monica
6
En Kotlin:@RunWith(MockitoJUnitRunner.Silent::class)
Juan Saravia
9
No estoy seguro de por qué esta respuesta sigue siendo votada sin una explicación. Otras respuestas son más significativas y precisas.
Yogesh
8
Esto no resuelve el problema, simplemente suprime el mensaje de error y también afectará a todas las demás pruebas (si las hay) en la clase.
Fencer
98

Primero debe verificar su lógica de prueba. Generalmente hay 3 casos. Primero, se está burlando de un método incorrecto (cometió un error tipográfico o alguien cambió el código probado para que el método burlado ya no se use). En segundo lugar, su prueba falla antes de que se llame a este método. En tercer lugar, su lógica falla si / switch branch en algún lugar del código para que no se llame al método simulado.

Si este es el primer caso, siempre desea cambiar el método simulado por el que se usa en el código. Con el segundo y el tercero depende. Por lo general, debe eliminar este simulacro si no tiene ningún uso. Pero a veces hay ciertos casos en las pruebas parametrizadas, que deberían tomar este camino diferente o fallar antes. Luego, puede dividir esta prueba en dos o más pruebas separadas, pero eso no siempre es atractivo. 3 métodos de prueba con posiblemente 3 proveedores de argumentos pueden hacer que la prueba parezca ilegible. En ese caso, para JUnit 4, silencia esta excepción con

@RunWith(MockitoJUnitRunner.Silent.class) 

anotación o si está utilizando el enfoque de reglas

@Rule
public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.LENIENT);

o (el mismo comportamiento)

@Rule
public MockitoRule rule = MockitoJUnit.rule().silent();

Para las pruebas de JUnit 5, puede silenciar esta excepción utilizando la anotación proporcionada en mockito-junit-jupiterpackage.

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class JUnit5MockitoTest {
}
Dcortez
fuente
3
@MockitoSettings (rigurosidad = Estricidad.LENIENTE) es la forma más sencilla de ajustar el rigor en mi configuración. ¡Gracias!
Matt
4
Esta respuesta proporciona una buena descripción general de las posibilidades. Sin embargo, también puede establecer el rigor indulgente caso por caso utilizando Mockito.lenient().when(...); para esta pregunta en particular seríaMockito.lenient().when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);
neXus
Defina ExtendWith en superclase y MockitoSettings en subclases, cuando se trate de jerarquías de prueba. Espero que esto le ahorre tiempo a alguien a mi costa.
miracle_the_V
34

Silencio no es una solución. Necesitas arreglar tu simulacro en tu prueba. Consulte la documentación oficial aquí .

Los stubs innecesarios son llamadas a métodos stubped que nunca se realizaron durante la ejecución de la prueba (ver también MockitoHint), ejemplo:

//code under test:
 ...
 String result = translator.translate("one")
 ...

 //test:
 ...
 when(translator.translate("one")).thenReturn("jeden"); // <- stubbing realized during code execution
 when(translator.translate("two")).thenReturn("dwa"); // <- stubbing never realized
 ...

Observe que uno de los métodos stubped nunca se realizó en el código bajo prueba durante la ejecución de la prueba. El stubbing perdido puede ser un descuido del desarrollador, el artefacto de copiar y pegar o el efecto de no entender la prueba / código. De cualquier manera, el desarrollador termina con un código de prueba innecesario. Para mantener el código base limpio y fácil de mantener, es necesario eliminar el código innecesario. De lo contrario, las pruebas son más difíciles de leer y razonar.

Para obtener más información sobre cómo detectar stubbings no utilizados, consulte MockitoHint.

Stéphane GRILLON
fuente
13
Hay muchas situaciones en las que escribe 8-9 pruebas en una configuración de @BeforeEach similar en la que el elemento devuelto de un código auxiliar no se utiliza debido a la lógica empresarial en un puñado de pruebas. Puede (A) dividirlo en múltiples pruebas y copiar / pegar de manera efectiva la sección \ @BeforeEach menos el elemento (B) Copiar / pegar la línea única que Mockito está emo sobre las 6 pruebas que la usan y la tienen no en los 2 que no lo hacen o (C) Use silencio. Prefiero usar silencio / advertencia. No es una prueba rota.
RockMeetHardplace
1
@RockMeetHardplace, Silent no es una solución , rápidamente verá menos copiar / pegar, pero al mantener sus pruebas por personas nuevas en su proyecto, esto será problemático. Si la librería Mockito lo hace no es por nada.
Stéphane GRILLON
2
@sgrillon: Pero este sistema detecta muchos falsos positivos. Es decir, dice que algo no se usa, pero claramente no lo está, ya que quitar el talón rompe la ejecución. No es que el código de prueba no se pueda mejorar, es que una línea vital de stubbing nunca debe detectarse como "innecesaria". De ahí la importancia de poder desactivar esta comprobación, es demasiado impaciente.
Carighan
@Carighan, si tu simulacro se detecta como incorrecta, puede que no sea lo que piensas. Esto le da una prueba correcta mientras puede haber un error.
Stéphane GRILLON
@sgrillon, lo siento, nunca te respondí sobre eso. Resulta que solía haber un error con esto en el que, dependiendo del orden de ejecución de la prueba, generaba "falsos aciertos", donde los stubs que se usaban en una prueba pero se sobrescribían en otra lo activaban. Sin embargo, hasta donde yo sé, está arreglado durante mucho tiempo.
Carighan
27

Para mí, @Ruleni las @RunWith(MockitoJUnitRunner.Silent.class)sugerencias ni las sugerencias funcionaron. Era un proyecto heredado en el que actualizamos a mockito-core 2.23.0.

Podríamos deshacernos del UnnecessaryStubbingExceptionusando:

Mockito.lenient().when(mockedService.getUserById(any())).thenReturn(new User());

en vez de:

when(mockedService.getUserById(any())).thenReturn(new User());

No hace falta decir que debería mirar el código de prueba, pero primero teníamos que compilar las cosas y ejecutar las pruebas;)

filono
fuente
6
EN MI HUMILDE OPINIÓN. Esta es la respuesta más útil aquí que encontré en lugar de silenciar a toda la clase de prueba.
priyeshdkr
Como quería suprimir solo una burla, esta es la mejor respuesta para mí. Sin embargo, no es realmente una respuesta para el OP.
Hans Wouters
25
 when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);//got error in this line
 verify(dao).doSearchInspections(dto);

El whenaquí configura su maqueta para hacer algo. Sin embargo, ya no usa este simulacro después de esta línea (aparte de hacer a verify). Mockito te advierte que la whenlínea, por tanto, no tiene sentido. ¿Quizás cometiste un error lógico?

john16384
fuente
Gracias por su ayuda
VHS
Necesito tanto cuándo y verificar declaraciones, sugerir amablemente cómo avanzar más
VHS
2
Llame a una función en su clase de prueba ( Service) para ver si reacciona correctamente. No hiciste eso en absoluto, entonces, ¿qué estás probando aquí?
john16384
3

Al mirar una parte del seguimiento de su pila, parece que está cortando el dao.doSearch()resto. Más como crear repetidamente los stubs del mismo método.

Following stubbings are unnecessary (click to navigate to relevant line of code):
  1. -> at service.Test.testDoSearch(Test.java:72)
Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class.

Considere la siguiente clase de prueba, por ejemplo:

@RunWith(MockitoJUnitRunner.class)
public class SomeTest {
    @Mock
    Service1 svc1Mock1;

    @Mock
    Service2 svc2Mock2;

    @InjectMock
    TestClass class;

    //Assume you have many dependencies and you want to set up all the stubs 
    //in one place assuming that all your tests need these stubs.

    //I know that any initialization code for the test can/should be in a 
    //@Before method. Lets assume there is another method just to create 
    //your stubs.

    public void setUpRequiredStubs() {
        when(svc1Mock1.someMethod(any(), any())).thenReturn(something));
        when(svc2Mock2.someOtherMethod(any())).thenReturn(somethingElse);
    }

    @Test
    public void methodUnderTest_StateUnderTest_ExpectedBehavior() {
        // You forget that you defined the stub for svcMock1.someMethod or 
        //thought you could redefine it. Well you cannot. That's going to be 
        //a problem and would throw your UnnecessaryStubbingException.
       when(svc1Mock1.someMethod(any(),any())).thenReturn(anyThing);//ERROR!
       setUpRequiredStubs();
    }
}

Prefiero considerar la posibilidad de refactorizar sus pruebas para stub donde sea necesario.

Railomaya
fuente
2

Si está usando este estilo en su lugar:

@Rule
public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);

reemplácelo con:

@Rule
public MockitoRule rule = MockitoJUnit.rule().silent();
Greg
fuente
2

Reemplazar

@RunWith(MockitoJUnitRunner.class)

con

@RunWith(MockitoJUnitRunner.Silent.class)

o quitar@RunWith(MockitoJUnitRunner.class)

o simplemente comente las llamadas burlonas no deseadas (mostradas como stubbing no autorizado).

Nakul Goyal
fuente
1

Lo hice UnnecessaryStubbingExceptioncuando intenté usar los whenmétodos en un objeto Spy. Mockito.lenient()silenciaron la excepción pero los resultados de la prueba no fueron correctos.

En el caso de objetos Spy, hay que llamar directamente a los métodos.

@ExtendWith(MockitoExtension.class)
@RunWith(JUnitPlatform.class)
class ArithmTest {

    @Spy
    private Arithm arithm;

    @Test
    void testAddition() {

        int res = arithm.add(2, 5);

        // doReturn(7).when(arithm).add(2, 5);
        assertEquals(res, 7);
    }
}
Jan Bodnar
fuente
1

Bueno, en mi caso, el error de Mockito me decía que llamara al método real después de whenor wheneverstub. Como no invocamos las condiciones de las que nos burlamos, Mockito lo reportó como códigos o códigos auxiliares innecesarios.

Así es como era cuando venía el error:

@Test
fun `should return error when item list is empty for getStockAvailability`() {
    doAnswer(
        Answer<Void> { invocation ->
            val callback =
                invocation.arguments[1] as GetStockApiCallback<StockResultViewState.Idle, StockResultViewState.Error>
            callback.onApiCallError(stockResultViewStateError)
            null
        }
    ).whenever(stockViewModelTest)
        .getStockAvailability(listOf(), getStocksApiCallBack)
}

luego llamé al método real mencionado en la declaración when para burlarse del método.

los cambios realizados son los siguientes stockViewModelTest.getStockAvailability(listOf(), getStocksApiCallBack)

@Test
fun `should return error when item list is empty for getStockAvailability`() {
    doAnswer(
        Answer<Void> { invocation ->
            val callback =
                invocation.arguments[1] as GetStockApiCallback<StockResultViewState.Idle, StockResultViewState.Error>
            callback.onApiCallError(stockResultViewStateError)
            null
        }
    ).whenever(stockViewModelTest)
        .getStockAvailability(listOf(), getStocksApiCallBack)
    //called the actual method here
    stockViewModelTest.getStockAvailability(listOf(), getStocksApiCallBack)
}

Está funcionando ahora.

vikas kumar
fuente
0

En el caso de un proyecto grande, es difícil corregir cada una de estas excepciones. Al mismo tiempo, Silentno se recomienda su uso. He escrito una secuencia de comandos para eliminar todos los stubbings innecesarios dada una lista de ellos.

https://gist.github.com/cueo/da1ca49e92679ac49f808c7ef594e75b

Solo necesitamos copiar y pegar la mvnsalida y escribir la lista de estas excepciones usando expresiones regulares y dejar que el script se encargue del resto.

mohitmayank
fuente
0

Si usa any () al burlarse, debe relacionar @RunWith (MockitoJUnitRunner.class) con @RunWith (MockitoJUnitRunner.Silent.class).

Abdou ASSOUMANE
fuente
0

Cuando crea un simulacro y ese simulacro no se usa, arroja una excepción de apéndice no utilizada. En su caso, ese simulacro no se llama realmente. Por eso está lanzando ese error. Por lo tanto, relpace @RunWith(MockitoJUnitRunner.class)con el @RunWith(MockitoJUnitRunner.Silent.class)que eliminaría el error. Si aún desea usar, @RunWith(MockitoJUnitRunner.class)intente depurar su lógica si la función de la que se ha burlado realmente se está llamando o no.

Shivam Kohli
fuente