java: discrepancia estricta en el argumento de creación de fragmentos cuando se usa @Value

CorePress2024-01-24  10

cualquier comparador() para el campo @Value genera un error de discrepancia en el argumento de creación estricta.

¿Existe algún ArgumentMatcher propio del campo @Value? ¿Y tal vez alguien sepa por qué 'any()' no funciona?

El campo (sampleVersion), que obtengo de application.properties usando la anotación @Value, tiene en la prueba un valor nulo (prueba: primera línea de registros). Incluso los registros muestran que hay un valor nulo y que el comparador espera un valor nulo.

PD: resolví este problema usando esto:

ReflectionTestUtils.setField(someClass, "serviceUrl", "value");

pero tengo curiosidad por saber si es necesario y por qué el simple any() no funciona.

Registros:

sampleVersion has value: null

Strict stubbing argument mismatch. Please check:
 - this invocation of 'postForEntity' method:
    restTemplate.postForEntity(
    null,
    <{key=null},[Content-Type:"application/json"]>,
    class java.lang.String
);
    -> at com.some.package.SomeClass.someMethod(SomeClass.java:126)
 - has following stubbing(s) with different arguments:
    1. restTemplate.postForEntity(null, null, null);
      -> at com.some.package.SomeClassTest.someTest(SomeClassTest.java:59)

Método:

    @Value("${sample.version}")
    private String sampleVersion;

    public ResponseEntity someMethod()  {

    System.out.println("sampleVersion has value: " + sampleVersion);

    Map<String, Object> paramMap = new HashMap<>();
    paramMap.put("key", sampleVersion);

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);

    return restTemplate.postForEntity(sampleVersion, new HttpEntity<>(paramMap, headers), String.class);
    }

Prueba:

    @InjectMocks
    SomeClass someClass = new SomeClass();

    @Test
    void someTest() {
    //given
    ResponseEntity response = new ResponseEntity("{ \"text\" : \"hello\"}", HttpStatus.OK);

    //when
    when(restTemplate.postForEntity(any(), any(), eq(String.class))).thenReturn(response);
    ResponseEntity responseEntity = someClass.someMethod();

    assertNotNull(responseEntity);
    }

Medio ambiente:

Java 11 SpringBoot 2.1.4 Mockito 2.27.0 Júpiter 5.3.2



------------------------------------

Hay 2 sobrecargas de postForEntity que podrían tomar 3 parámetros:

<T> EntidadRespuesta<T> postForEntity(URL de cadena, Solicitud de objeto, Clase<T> tipo de respuesta, Objeto... uriVariables) <T> EntidadRespuesta<T> postForEntity(URL URI, solicitud de objeto, clase<T> tipo de respuesta)

En tu código de producción, estás llamando al primero.

En tu prueba, eliminas el segundo. Esto se debe al hecho de que en su llamada:

when(restTemplate.postForEntity(any(), any(), eq(String.class))).thenReturn(response);

Usted proporciona 3 argumentos y los valores proporcionados coinciden con los tipos de parámetros de la segunda sobrecarga. Por lo tanto, ni siquiera se considera la sobrecarga con varargs. (any() devuelve nulo, lo cual es una buena coincidencia tanto para URI como para cadena).

En lugar dereflexión, le aconsejaría:

utilizar la inyección de constructor para sampleVersion suelte @InjectMocks en el servicio bajo prueba en su lugar, cree el servicio bajo prueba en un método BeforeEach.



------------------------------------

Escribo esto en las respuestas porque el autor puso la solución en la pregunta. (Esto es para una mejor visibilidad). El autor pudo resolver el problema usando

ReflectionTestUtils.setField(someClass, "field", "value");

Esto puede asignar un valor al campo privado con fines de prueba. El valor no lo asigna la anotación @Value durante la prueba automatizada.

Para obtener más información sobre el uso: https://www.baeldung.com/spring-reflexión-test-utils#uso-reflexióntestutils-para-establecer-un-valor-de-un-campo-no-público

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare