I try to write JUnit integration test and to test whether service method works well. It isn't.

This is the service class:
107 Replies
JavaBot
JavaBot3mo ago
This post has been reserved for your question.
Hey @Tomasm21! Please use /close or the Close Post button above when your problem is solved. Please remember to follow the help guidelines. This post will be automatically closed after 300 minutes of inactivity.
TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.
Tomasm21
Tomasm21OP3mo ago
@Service
public class ValidateCaptcha {

private static final Logger LOG = LoggerFactory.getLogger(ValidateCaptcha.class);

private final RestTemplate template;

@Value("${google.recaptcha.verification.endpoint}")
String recaptchaEndpoint;

@Value("${google.recaptcha.secret}")
String recaptchaSecret;

public ValidateCaptcha(final RestTemplateBuilder templateBuilder) {
this.template = templateBuilder.build();
}
@Service
public class ValidateCaptcha {

private static final Logger LOG = LoggerFactory.getLogger(ValidateCaptcha.class);

private final RestTemplate template;

@Value("${google.recaptcha.verification.endpoint}")
String recaptchaEndpoint;

@Value("${google.recaptcha.secret}")
String recaptchaSecret;

public ValidateCaptcha(final RestTemplateBuilder templateBuilder) {
this.template = templateBuilder.build();
}
/**
* Method to validate the captcha response coming from the client
* and to return either true or false after the validation.
* Reference url - https://developers.google.com/recaptcha/docs/verify
* @param captchaResponse
* @return boolean
*/
public boolean validateCaptcha(final String captchaResponse) {
LOG.info("RestTemplate instance: {}", template);
LOG.info("Going to validate the captcha response = [{}]", captchaResponse);
final MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
// "secret" is a required param and it represents the shared key between your site and the recaptcha.
params.add("secret", recaptchaSecret);

// "response" is a required param and it represents the user token provided
// by the recaptcha client-side integration on your site.
params.add("response", captchaResponse);

CaptchaResponse apiResponse = null;
try {
apiResponse = template.postForObject(recaptchaEndpoint, params, CaptchaResponse.class);
} catch (final RestClientException e) {
LOG.error("Some exception occurred while binding to the recaptcha endpoint.\n[{}]", e);
}

if (Objects.nonNull(apiResponse) && apiResponse.isSuccess()) {
LOG.info("Captcha API response = [{}]", apiResponse.toString());
return true;
} else {
return false;
}
}
}
/**
* Method to validate the captcha response coming from the client
* and to return either true or false after the validation.
* Reference url - https://developers.google.com/recaptcha/docs/verify
* @param captchaResponse
* @return boolean
*/
public boolean validateCaptcha(final String captchaResponse) {
LOG.info("RestTemplate instance: {}", template);
LOG.info("Going to validate the captcha response = [{}]", captchaResponse);
final MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
// "secret" is a required param and it represents the shared key between your site and the recaptcha.
params.add("secret", recaptchaSecret);

// "response" is a required param and it represents the user token provided
// by the recaptcha client-side integration on your site.
params.add("response", captchaResponse);

CaptchaResponse apiResponse = null;
try {
apiResponse = template.postForObject(recaptchaEndpoint, params, CaptchaResponse.class);
} catch (final RestClientException e) {
LOG.error("Some exception occurred while binding to the recaptcha endpoint.\n[{}]", e);
}

if (Objects.nonNull(apiResponse) && apiResponse.isSuccess()) {
LOG.info("Captcha API response = [{}]", apiResponse.toString());
return true;
} else {
return false;
}
}
}
This is the test:
@ExtendWith(MockitoExtension.class)
@SpringBootTest
public class ValidateCaptchaTest {

@Mock
private RestTemplate restTemplate;

@Autowired
private ValidateCaptcha validateCaptcha;

@Test
public void testValidateCaptcha() {
String captchaResponse = "test-captcha-response";

CaptchaResponse mockResponse = new CaptchaResponse();
mockResponse.setSuccess(true); // Set success or failure based on your test scenario

when(restTemplate.postForObject(
anyString(), // Mock any URL (recaptchaEndpoint)
any(MultiValueMap.class), // Mock any request params
eq(CaptchaResponse.class) // Expect a response of type CaptchaResponse
)).thenReturn(mockResponse);

boolean result = validateCaptcha.validateCaptcha(captchaResponse);

// Debug output to see what's happening
System.out.println("Captcha API call result: " + result);

assertTrue(result); // or assertFalse depending on mockResponse success
}
}
@ExtendWith(MockitoExtension.class)
@SpringBootTest
public class ValidateCaptchaTest {

@Mock
private RestTemplate restTemplate;

@Autowired
private ValidateCaptcha validateCaptcha;

@Test
public void testValidateCaptcha() {
String captchaResponse = "test-captcha-response";

CaptchaResponse mockResponse = new CaptchaResponse();
mockResponse.setSuccess(true); // Set success or failure based on your test scenario

when(restTemplate.postForObject(
anyString(), // Mock any URL (recaptchaEndpoint)
any(MultiValueMap.class), // Mock any request params
eq(CaptchaResponse.class) // Expect a response of type CaptchaResponse
)).thenReturn(mockResponse);

boolean result = validateCaptcha.validateCaptcha(captchaResponse);

// Debug output to see what's happening
System.out.println("Captcha API call result: " + result);

assertTrue(result); // or assertFalse depending on mockResponse success
}
}
Tomasm21
Tomasm21OP3mo ago
No description
Tomasm21
Tomasm21OP3mo ago
Console output:
Tomasm21
Tomasm21OP3mo ago
Am I doing anything wrong in the test? Or it cannot be tested like this? The application works well. When requesting from the frontend with the specific captchaResponse string the method returns true. But I want to test this method like a JUnit test. It should assert to true, but it is false. Why? I though mocked rest template already set the response. Looks like the service method is invoked for real. Should it be like this?
straightface
straightface3mo ago
you are not injecting resttemplate in your service class
Tomasm21
Tomasm21OP3mo ago
Isn't injected via constructor?
straightface
straightface3mo ago
yes but your constructor takes in a builer you do not have a builder
Tomasm21
Tomasm21OP3mo ago
The builder is imported import org.springframework.boot.web.client.RestTemplateBuilder; I don't know its implementation
straightface
straightface3mo ago
change the constructor to resttemplate instead
Tomasm21
Tomasm21OP3mo ago
You mean:
//...
private final RestTemplate template;
//...
public ValidateCaptcha(final RestTemplateBuilder templateBuilder) {
this.template = templateBuilder.build();
}

public ValidateCaptcha() {
this.template = new RestTemplate();
}
//...
private final RestTemplate template;
//...
public ValidateCaptcha(final RestTemplateBuilder templateBuilder) {
this.template = templateBuilder.build();
}

public ValidateCaptcha() {
this.template = new RestTemplate();
}
two constructors?
straightface
straightface3mo ago
no only one
Tomasm21
Tomasm21OP3mo ago
or to remove the one that us using the builder?
straightface
straightface3mo ago
yes modify to take in resttemplate
Tomasm21
Tomasm21OP3mo ago
The same:
No description
straightface
straightface3mo ago
public ValidateCaptcha(final RestTemplate template) { // <--- you inject this
this.template = template;
}
public ValidateCaptcha(final RestTemplate template) { // <--- you inject this
this.template = template;
}
Tomasm21
Tomasm21OP3mo ago
ahh lol Now I get the exception:
***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in it.akademija.recaptcha.ValidateCaptcha required a bean of type 'org.springframework.web.client.RestTemplate' that could not be found.

The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'org.springframework.web.client.RestTemplate' in your configuration.

2024-09-13 19:12:01.991 ERROR 10580 --- [ main] o.s.test.context.TestContextManager : Caught exception while allowing TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@60f7cc1d] to prepare test instance [it.akademija.recaptcha.ValidateCaptchaTest@7901a5ab]

java.lang.IllegalStateException: Failed to load ApplicationContext
//...
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'validateCaptcha' defined in file [G:\Java_programavimas\Mokyklos-projektas\Project\Maitinimas-back\target\classes\it\akademija\recaptcha\ValidateCaptcha.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.web.client.RestTemplate' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in it.akademija.recaptcha.ValidateCaptcha required a bean of type 'org.springframework.web.client.RestTemplate' that could not be found.

The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'org.springframework.web.client.RestTemplate' in your configuration.

2024-09-13 19:12:01.991 ERROR 10580 --- [ main] o.s.test.context.TestContextManager : Caught exception while allowing TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@60f7cc1d] to prepare test instance [it.akademija.recaptcha.ValidateCaptchaTest@7901a5ab]

java.lang.IllegalStateException: Failed to load ApplicationContext
//...
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'validateCaptcha' defined in file [G:\Java_programavimas\Mokyklos-projektas\Project\Maitinimas-back\target\classes\it\akademija\recaptcha\ValidateCaptcha.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.web.client.RestTemplate' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Should I add the bean to configuration? the rest tamplate lets see
straightface
straightface3mo ago
@InjectMocks
private ValidateCaptcha validateCaptcha;
@InjectMocks
private ValidateCaptcha validateCaptcha;
Tomasm21
Tomasm21OP3mo ago
Same:
No description
Tomasm21
Tomasm21OP3mo ago
In order the application to run I had to add the bean to configuration class:
@Bean
public RestTemplate restTemplateBean() {
return new RestTemplate();
}
@Bean
public RestTemplate restTemplateBean() {
return new RestTemplate();
}
Tomasm21
Tomasm21OP3mo ago
From frontend the reCapture works:
No description
Tomasm21
Tomasm21OP3mo ago
No description
Tomasm21
Tomasm21OP3mo ago
Maybe the service method cannot be tested like this? It is calling to the public URL for real. But in mock case it shouldn't. Strange
straightface
straightface3mo ago
@BeforeEach // replace with junit5 equivalent
void setUp() {
MockitoAnnotations.initMocks(this);
validateCaptcha= new ValidateCaptcha (restTemplate);
}
@BeforeEach // replace with junit5 equivalent
void setUp() {
MockitoAnnotations.initMocks(this);
validateCaptcha= new ValidateCaptcha (restTemplate);
}
its because you are not injecting mock you need to inject mock for it to work
Tomasm21
Tomasm21OP3mo ago
JUnit testing is not my strong side. I do it rarely. Ok now I get error:
org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:
- this invocation of 'postForObject' method:
restTemplate.postForObject(
null,
{"secret" = [null], "response" = [test-captcha-response]},
class it.akademija.recaptcha.CaptchaResponse
);
-> at it.akademija.recaptcha.ValidateCaptcha.validateCaptcha(ValidateCaptcha.java:57)
- has following stubbing(s) with different arguments:
1. restTemplate.postForObject("", null, null);
-> at it.akademija.recaptcha.ValidateCaptchaTest.testValidateCaptcha(ValidateCaptchaTest.java:46)
Typically, stubbing argument mismatch indicates user mistake when writing tests.
Mockito fails early so that you can debug potential problem easily.
However, there are legit scenarios when this exception generates false negative signal:
- stubbing the same method multiple times using 'given().will()' or 'when().then()' API
Please use 'will().given()' or 'doReturn().when()' API for stubbing.
- stubbed method is intentionally invoked with different arguments by code under test
Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).
For more information see javadoc for PotentialStubbingProblem class.
at it.akademija.recaptcha.ValidateCaptcha.validateCaptcha(ValidateCaptcha.java:57)
at it.akademija.recaptcha.ValidateCaptchaTest.testValidateCaptcha(ValidateCaptchaTest.java:52)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:
- this invocation of 'postForObject' method:
restTemplate.postForObject(
null,
{"secret" = [null], "response" = [test-captcha-response]},
class it.akademija.recaptcha.CaptchaResponse
);
-> at it.akademija.recaptcha.ValidateCaptcha.validateCaptcha(ValidateCaptcha.java:57)
- has following stubbing(s) with different arguments:
1. restTemplate.postForObject("", null, null);
-> at it.akademija.recaptcha.ValidateCaptchaTest.testValidateCaptcha(ValidateCaptchaTest.java:46)
Typically, stubbing argument mismatch indicates user mistake when writing tests.
Mockito fails early so that you can debug potential problem easily.
However, there are legit scenarios when this exception generates false negative signal:
- stubbing the same method multiple times using 'given().will()' or 'when().then()' API
Please use 'will().given()' or 'doReturn().when()' API for stubbing.
- stubbed method is intentionally invoked with different arguments by code under test
Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).
For more information see javadoc for PotentialStubbingProblem class.
at it.akademija.recaptcha.ValidateCaptcha.validateCaptcha(ValidateCaptcha.java:57)
at it.akademija.recaptcha.ValidateCaptchaTest.testValidateCaptcha(ValidateCaptchaTest.java:52)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Tomasm21
Tomasm21OP3mo ago
No description
Tomasm21
Tomasm21OP3mo ago
I guess i should provide the secret I should add more things What are those stubbings? The parameters for restTemplate.postForObject( ? I have empty string and null for the second and third parameters? And it asks that I would give right type parameters and not nulls? I will try it.
straightface
straightface3mo ago
@MockitoSettings(strictness = Strictness.LENIENT) try adding this annotation to your test class
Tomasm21
Tomasm21OP3mo ago
ok.. hold on You mean like this:
@MockitoSettings(strictness = Strictness.LENIENT)
@ExtendWith(MockitoExtension.class)
@SpringBootTest
public class ValidateCaptchaTest {
@MockitoSettings(strictness = Strictness.LENIENT)
@ExtendWith(MockitoExtension.class)
@SpringBootTest
public class ValidateCaptchaTest {
?
straightface
straightface3mo ago
yes
Tomasm21
Tomasm21OP3mo ago
No description
Tomasm21
Tomasm21OP3mo ago
It's already 2024-09-13 19:55:25.955 INFO 10884 --- [ main] it.akademija.recaptcha.ValidateCaptcha : RestTemplate instance: restTemplate earlier it was: 2024-09-13 18:32:18.109 INFO 1392 --- [ main] it.akademija.recaptcha.ValidateCaptcha : RestTemplate instance: org.springframework.web.client.RestTemplate@2db0dd19
straightface
straightface3mo ago
wait let me try to reproduce it at my end
Tomasm21
Tomasm21OP3mo ago
Should I give you the project? Ok. will wait
straightface
straightface3mo ago
when(restTemplate.postForObject(
anyString(), // Mock any URL (recaptchaEndpoint)
any(MultiValueMap.class), // Mock any request params
eq(CaptchaResponse.class) // Expect a response of type CaptchaResponse
)).thenReturn(mockResponse);
when(restTemplate.postForObject(
anyString(), // Mock any URL (recaptchaEndpoint)
any(MultiValueMap.class), // Mock any request params
eq(CaptchaResponse.class) // Expect a response of type CaptchaResponse
)).thenReturn(mockResponse);
can you provide me import for eq here?
Tomasm21
Tomasm21OP3mo ago
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.eq;
Or do you need CaptchaResponse class?
straightface
straightface3mo ago
this
Tomasm21
Tomasm21OP3mo ago
this, - I understand like the import string import static org.mockito.ArgumentMatchers.eq;. Ok
straightface
straightface3mo ago
ok so this works
@ExtendWith(MockitoExtension.class)
class HttpBinTest {

@Mock
RestTemplate restTemplate;

@Autowired
private HttpBin validateCaptcha;

@BeforeEach
// replace with junit5 equivalent
void setUp() {

MockitoAnnotations.initMocks(this);
validateCaptcha = new HttpBin(restTemplate);
}

@Test
void validateCaptcha() {

when(restTemplate.postForObject(
anyString(), // Mock any URL (recaptchaEndpoint)
any(Object.class), // Mock any request params
eq(String.class // Expect a response of type CaptchaResponse
))).thenReturn("world");
System.out.println(validateCaptcha.validateCaptcha("hello"));
}
}
@ExtendWith(MockitoExtension.class)
class HttpBinTest {

@Mock
RestTemplate restTemplate;

@Autowired
private HttpBin validateCaptcha;

@BeforeEach
// replace with junit5 equivalent
void setUp() {

MockitoAnnotations.initMocks(this);
validateCaptcha = new HttpBin(restTemplate);
}

@Test
void validateCaptcha() {

when(restTemplate.postForObject(
anyString(), // Mock any URL (recaptchaEndpoint)
any(Object.class), // Mock any request params
eq(String.class // Expect a response of type CaptchaResponse
))).thenReturn("world");
System.out.println(validateCaptcha.validateCaptcha("hello"));
}
}
Tomasm21
Tomasm21OP3mo ago
without SpringBootTest... I thought so..
straightface
straightface3mo ago
I removed spring crap and just manually added mock resttemplate
Tomasm21
Tomasm21OP3mo ago
ok, testing
Tomasm21
Tomasm21OP3mo ago
No. it's still false:
No description
Tomasm21
Tomasm21OP3mo ago
@MockitoSettings(strictness = Strictness.LENIENT)
@ExtendWith(MockitoExtension.class)
public class ValidateCaptchaTest {

@Mock
private RestTemplate restTemplate;

@Autowired
private ValidateCaptcha validateCaptcha;

@SuppressWarnings("deprecation")
@BeforeEach // replace with junit5 equivalent
void setUp() {
MockitoAnnotations.initMocks(this);
validateCaptcha= new ValidateCaptcha (restTemplate);
}

@Test
public void testValidateCaptcha() {
String captchaResponse = "test-captcha-response";

CaptchaResponse mockResponse = new CaptchaResponse();
mockResponse.setSuccess(true); // Set success or failure based on your test scenario

when(restTemplate.postForObject(
anyString(), // Mock any URL (recaptchaEndpoint)
any(MultiValueMap.class), // Mock any request params
eq(CaptchaResponse.class) // Expect a response of type CaptchaResponse
)).thenReturn(mockResponse);

boolean result = validateCaptcha.validateCaptcha(captchaResponse);

// Debug output to see what's happening
System.out.println("Captcha API call result: " + result);

assertTrue(result); // or assertFalse depending on mockResponse success
}
}
@MockitoSettings(strictness = Strictness.LENIENT)
@ExtendWith(MockitoExtension.class)
public class ValidateCaptchaTest {

@Mock
private RestTemplate restTemplate;

@Autowired
private ValidateCaptcha validateCaptcha;

@SuppressWarnings("deprecation")
@BeforeEach // replace with junit5 equivalent
void setUp() {
MockitoAnnotations.initMocks(this);
validateCaptcha= new ValidateCaptcha (restTemplate);
}

@Test
public void testValidateCaptcha() {
String captchaResponse = "test-captcha-response";

CaptchaResponse mockResponse = new CaptchaResponse();
mockResponse.setSuccess(true); // Set success or failure based on your test scenario

when(restTemplate.postForObject(
anyString(), // Mock any URL (recaptchaEndpoint)
any(MultiValueMap.class), // Mock any request params
eq(CaptchaResponse.class) // Expect a response of type CaptchaResponse
)).thenReturn(mockResponse);

boolean result = validateCaptcha.validateCaptcha(captchaResponse);

// Debug output to see what's happening
System.out.println("Captcha API call result: " + result);

assertTrue(result); // or assertFalse depending on mockResponse success
}
}
straightface
straightface3mo ago
add a breakpoint
if (Objects.nonNull(apiResponse) && apiResponse.isSuccess()) {
LOG.info("Captcha API response = [{}]", apiResponse.toString());
return true;
}
if (Objects.nonNull(apiResponse) && apiResponse.isSuccess()) {
LOG.info("Captcha API response = [{}]", apiResponse.toString());
return true;
}
and check value for apiResponse
Tomasm21
Tomasm21OP3mo ago
I never debuugged. teach me. I added the break point and launcged the test in debugging mode. Howered I don't know where to look for the apiResponse value:
No description
straightface
straightface3mo ago
there should be a variables window somewhere in right that panel shows all variables in that
Tomasm21
Tomasm21OP3mo ago
No description
Tomasm21
Tomasm21OP3mo ago
it's null
straightface
straightface3mo ago
hmm i see, expand this and see id for resttemplate
Tomasm21
Tomasm21OP3mo ago
No description
Tomasm21
Tomasm21OP3mo ago
I run it once more when showing latest image
straightface
straightface3mo ago
any(MultiValueMap.class), change this to any(Object.class)
Tomasm21
Tomasm21OP3mo ago
It was already Object:
Tomasm21
Tomasm21OP3mo ago
No description
Tomasm21
Tomasm21OP3mo ago
I will change to MultiValueMap.class ok?
straightface
straightface3mo ago
yes remove @MockitoSettings(strictness = Strictness.LENIENT) as well we need those errors
Tomasm21
Tomasm21OP3mo ago
I will test it in debug mode like this now:
No description
Tomasm21
Tomasm21OP3mo ago
No description
Tomasm21
Tomasm21OP3mo ago
stubbing
org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:
- this invocation of 'postForObject' method:
restTemplate.postForObject(
null,
{"secret" = [null], "response" = [test-captcha-response]},
class it.akademija.recaptcha.CaptchaResponse
);
-> at it.akademija.recaptcha.ValidateCaptcha.validateCaptcha(ValidateCaptcha.java:57)
- has following stubbing(s) with different arguments:
1. restTemplate.postForObject("", null, null);
-> at it.akademija.recaptcha.ValidateCaptchaTest.testValidateCaptcha(ValidateCaptchaTest.java:48)
Typically, stubbing argument mismatch indicates user mistake when writing tests.
Mockito fails early so that you can debug potential problem easily.
However, there are legit scenarios when this exception generates false negative signal:
- stubbing the same method multiple times using 'given().will()' or 'when().then()' API
Please use 'will().given()' or 'doReturn().when()' API for stubbing.
- stubbed method is intentionally invoked with different arguments by code under test
Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).
For more information see javadoc for PotentialStubbingProblem class.
at it.akademija.recaptcha.ValidateCaptcha.validateCaptcha(ValidateCaptcha.java:57)
at it.akademija.recaptcha.ValidateCaptchaTest.testValidateCaptcha(ValidateCaptchaTest.java:54)
org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:
- this invocation of 'postForObject' method:
restTemplate.postForObject(
null,
{"secret" = [null], "response" = [test-captcha-response]},
class it.akademija.recaptcha.CaptchaResponse
);
-> at it.akademija.recaptcha.ValidateCaptcha.validateCaptcha(ValidateCaptcha.java:57)
- has following stubbing(s) with different arguments:
1. restTemplate.postForObject("", null, null);
-> at it.akademija.recaptcha.ValidateCaptchaTest.testValidateCaptcha(ValidateCaptchaTest.java:48)
Typically, stubbing argument mismatch indicates user mistake when writing tests.
Mockito fails early so that you can debug potential problem easily.
However, there are legit scenarios when this exception generates false negative signal:
- stubbing the same method multiple times using 'given().will()' or 'when().then()' API
Please use 'will().given()' or 'doReturn().when()' API for stubbing.
- stubbed method is intentionally invoked with different arguments by code under test
Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).
For more information see javadoc for PotentialStubbingProblem class.
at it.akademija.recaptcha.ValidateCaptcha.validateCaptcha(ValidateCaptcha.java:57)
at it.akademija.recaptcha.ValidateCaptchaTest.testValidateCaptcha(ValidateCaptchaTest.java:54)
I guess I needto provide URL string, Multivalue map parameters
straightface
straightface3mo ago
do you have equals and hashcode in CaptchaResponse ?
Tomasm21
Tomasm21OP3mo ago
No.
public class CaptchaResponse {
boolean success;
LocalDateTime challenge_ts;
String hostname;
@JsonProperty("error-codes")
List<String> errorCodes;

public CaptchaResponse() {}

public CaptchaResponse(boolean success, LocalDateTime challenge_ts, String hostname, List<String> errorCodes) {
super();
this.success = success;
this.challenge_ts = challenge_ts;
this.hostname = hostname;
this.errorCodes = errorCodes;
}

public boolean isSuccess() {
return success;
}

public void setSuccess(boolean success) {
this.success = success;
}

public LocalDateTime getChallenge_ts() {
return challenge_ts;
}

public void setChallenge_ts(LocalDateTime challenge_ts) {
this.challenge_ts = challenge_ts;
}

public String getHostname() {
return hostname;
}

public void setHostname(String hostname) {
this.hostname = hostname;
}

public List<String> getErrorCodes() {
return errorCodes;
}

public void setErrorCodes(List<String> errorCodes) {
this.errorCodes = errorCodes;
}

@Override
public String toString() {
return "CaptchaResponse [success=" + success + ", challenge_ts=" + challenge_ts + ", hostname=" + hostname
+ ", errorCodes=" + errorCodes + "]";
}

}
public class CaptchaResponse {
boolean success;
LocalDateTime challenge_ts;
String hostname;
@JsonProperty("error-codes")
List<String> errorCodes;

public CaptchaResponse() {}

public CaptchaResponse(boolean success, LocalDateTime challenge_ts, String hostname, List<String> errorCodes) {
super();
this.success = success;
this.challenge_ts = challenge_ts;
this.hostname = hostname;
this.errorCodes = errorCodes;
}

public boolean isSuccess() {
return success;
}

public void setSuccess(boolean success) {
this.success = success;
}

public LocalDateTime getChallenge_ts() {
return challenge_ts;
}

public void setChallenge_ts(LocalDateTime challenge_ts) {
this.challenge_ts = challenge_ts;
}

public String getHostname() {
return hostname;
}

public void setHostname(String hostname) {
this.hostname = hostname;
}

public List<String> getErrorCodes() {
return errorCodes;
}

public void setErrorCodes(List<String> errorCodes) {
this.errorCodes = errorCodes;
}

@Override
public String toString() {
return "CaptchaResponse [success=" + success + ", challenge_ts=" + challenge_ts + ", hostname=" + hostname
+ ", errorCodes=" + errorCodes + "]";
}

}
straightface
straightface3mo ago
implement and try
Tomasm21
Tomasm21OP3mo ago
generated:
@Override
public int hashCode() {
return Objects.hash(challenge_ts, errorCodes, hostname, success);
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CaptchaResponse other = (CaptchaResponse) obj;
return Objects.equals(challenge_ts, other.challenge_ts) && Objects.equals(errorCodes, other.errorCodes)
&& Objects.equals(hostname, other.hostname) && success == other.success;
}
@Override
public int hashCode() {
return Objects.hash(challenge_ts, errorCodes, hostname, success);
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CaptchaResponse other = (CaptchaResponse) obj;
return Objects.equals(challenge_ts, other.challenge_ts) && Objects.equals(errorCodes, other.errorCodes)
&& Objects.equals(hostname, other.hostname) && success == other.success;
}
trying Same:
org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:
- this invocation of 'postForObject' method:
restTemplate.postForObject(
null,
{"secret" = [null], "response" = [test-captcha-response]},
class it.akademija.recaptcha.CaptchaResponse
);
-> at it.akademija.recaptcha.ValidateCaptcha.validateCaptcha(ValidateCaptcha.java:57)
- has following stubbing(s) with different arguments:
1. restTemplate.postForObject("", null, null);
-> at it.akademija.recaptcha.ValidateCaptchaTest.testValidateCaptcha(ValidateCaptchaTest.java:48)
Typically, stubbing argument mismatch indicates user mistake when writing tests.
Mockito fails early so that you can debug potential problem easily.
However, there are legit scenarios when this exception generates false negative signal:
- stubbing the same method multiple times using 'given().will()' or 'when().then()' API
Please use 'will().given()' or 'doReturn().when()' API for stubbing.
- stubbed method is intentionally invoked with different arguments by code under test
Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).
For more information see javadoc for PotentialStubbingProblem class.
at it.akademija.recaptcha.ValidateCaptcha.validateCaptcha(ValidateCaptcha.java:57)
at it.akademija.recaptcha.ValidateCaptchaTest.testValidateCaptcha(ValidateCaptchaTest.java:54)
org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:
- this invocation of 'postForObject' method:
restTemplate.postForObject(
null,
{"secret" = [null], "response" = [test-captcha-response]},
class it.akademija.recaptcha.CaptchaResponse
);
-> at it.akademija.recaptcha.ValidateCaptcha.validateCaptcha(ValidateCaptcha.java:57)
- has following stubbing(s) with different arguments:
1. restTemplate.postForObject("", null, null);
-> at it.akademija.recaptcha.ValidateCaptchaTest.testValidateCaptcha(ValidateCaptchaTest.java:48)
Typically, stubbing argument mismatch indicates user mistake when writing tests.
Mockito fails early so that you can debug potential problem easily.
However, there are legit scenarios when this exception generates false negative signal:
- stubbing the same method multiple times using 'given().will()' or 'when().then()' API
Please use 'will().given()' or 'doReturn().when()' API for stubbing.
- stubbed method is intentionally invoked with different arguments by code under test
Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).
For more information see javadoc for PotentialStubbingProblem class.
at it.akademija.recaptcha.ValidateCaptcha.validateCaptcha(ValidateCaptcha.java:57)
at it.akademija.recaptcha.ValidateCaptchaTest.testValidateCaptcha(ValidateCaptchaTest.java:54)
straightface
straightface3mo ago
is your recaptchaEndpoint null? it should be string it is, thats the problem...bruh
Tomasm21
Tomasm21OP3mo ago
checking.. wait a moment I thing it is that first parameter:
when(restTemplate.postForObject(
anyString(), // Mock any URL (recaptchaEndpoint)
any(MultiValueMap.class), // Mock any request params
eq(CaptchaResponse.class) // Expect a response of type CaptchaResponse
)).thenReturn(mockResponse);
when(restTemplate.postForObject(
anyString(), // Mock any URL (recaptchaEndpoint)
any(MultiValueMap.class), // Mock any request params
eq(CaptchaResponse.class) // Expect a response of type CaptchaResponse
)).thenReturn(mockResponse);
the anyString().
straightface
straightface3mo ago
nope, your service class you are injecting it and its null just set some value temporarily and then test
Tomasm21
Tomasm21OP3mo ago
during runtime it is taken from environment:
@Value("${google.recaptcha.verification.endpoint}")
String recaptchaEndpoint;
@Value("${google.recaptcha.verification.endpoint}")
String recaptchaEndpoint;
in application.properties it is: google.recaptcha.verification.endpoint=https://www.google.com/recaptcha/api/siteverify
straightface
straightface3mo ago
yes but we dont have spring here, so it is just null thats causing the issue
Tomasm21
Tomasm21OP3mo ago
So how to set it up?
straightface
straightface3mo ago
always constructor inject just like resttemplate
Tomasm21
Tomasm21OP3mo ago
IS this ok:
No description
straightface
straightface3mo ago
yep
Tomasm21
Tomasm21OP3mo ago
ok will test and it test I need to write it too
straightface
straightface3mo ago
what?
Tomasm21
Tomasm21OP3mo ago
No description
Tomasm21
Tomasm21OP3mo ago
in test class, due to constructor change I have to add the second parameter Right?
straightface
straightface3mo ago
yes... and well run and check
Tomasm21
Tomasm21OP3mo ago
ok..
straightface
straightface3mo ago
thats whats tests are for
Tomasm21
Tomasm21OP3mo ago
No description
Tomasm21
Tomasm21OP3mo ago
same error damn it
straightface
straightface3mo ago
again we removed spring that @value wont work what do you put there instead?
Tomasm21
Tomasm21OP3mo ago
I will put the actual URL the "https://www.google.com/recaptcha/api/siteverify"
straightface
straightface3mo ago
just think... any string will work we dont invoke that url at all but yeah actual url will also work
Tomasm21
Tomasm21OP3mo ago
Debug:
No description
straightface
straightface3mo ago
resume
Tomasm21
Tomasm21OP3mo ago
And test:
No description
Tomasm21
Tomasm21OP3mo ago
🙂 Thanks
straightface
straightface3mo ago
finally, lol
Tomasm21
Tomasm21OP3mo ago
Is the test correct without launchig the Spring Boot container
straightface
straightface3mo ago
you tell me, does it test business logic? that you intended to test?
Tomasm21
Tomasm21OP3mo ago
I have also successful controller test, So I reckon that yes
@SpringBootTest
@AutoConfigureMockMvc
class RecaptureControllerTest {

@Autowired
private MockMvc mockMvc;

@MockBean
private ValidateCaptcha validateCaptcha;

@Test
void whenValidCaptcha_thenReturnTrue() throws Exception {
// Mocking the service call
Mockito.when(validateCaptcha.validateCaptcha(Mockito.anyString())).thenReturn(true);

RecaptchaDTO dto = new RecaptchaDTO("testCaptchaResponse");

mockMvc.perform(post("/api/verify")
.contentType(MediaType.APPLICATION_JSON)
.content(new ObjectMapper().writeValueAsString(dto)))
.andExpect(status().isOk())
.andExpect(content().string("true")); // Expecting true for valid captcha
}

@Test
void whenInvalidCaptcha_thenReturnFalse() throws Exception {
// Mocking the service call
Mockito.when(validateCaptcha.validateCaptcha(Mockito.anyString())).thenReturn(false);

RecaptchaDTO dto = new RecaptchaDTO("invalidCaptchaResponse");

mockMvc.perform(post("/api/verify")
.contentType(MediaType.APPLICATION_JSON)
.content(new ObjectMapper().writeValueAsString(dto)))
.andExpect(status().isOk())
.andExpect(content().string("false")); // Expecting false for invalid captcha
}
}
@SpringBootTest
@AutoConfigureMockMvc
class RecaptureControllerTest {

@Autowired
private MockMvc mockMvc;

@MockBean
private ValidateCaptcha validateCaptcha;

@Test
void whenValidCaptcha_thenReturnTrue() throws Exception {
// Mocking the service call
Mockito.when(validateCaptcha.validateCaptcha(Mockito.anyString())).thenReturn(true);

RecaptchaDTO dto = new RecaptchaDTO("testCaptchaResponse");

mockMvc.perform(post("/api/verify")
.contentType(MediaType.APPLICATION_JSON)
.content(new ObjectMapper().writeValueAsString(dto)))
.andExpect(status().isOk())
.andExpect(content().string("true")); // Expecting true for valid captcha
}

@Test
void whenInvalidCaptcha_thenReturnFalse() throws Exception {
// Mocking the service call
Mockito.when(validateCaptcha.validateCaptcha(Mockito.anyString())).thenReturn(false);

RecaptchaDTO dto = new RecaptchaDTO("invalidCaptchaResponse");

mockMvc.perform(post("/api/verify")
.contentType(MediaType.APPLICATION_JSON)
.content(new ObjectMapper().writeValueAsString(dto)))
.andExpect(status().isOk())
.andExpect(content().string("false")); // Expecting false for invalid captcha
}
}
this one works
straightface
straightface3mo ago
btw you can start to add spring back now
Tomasm21
Tomasm21OP3mo ago
what?
straightface
straightface3mo ago
yeah we got the root issue for why mockito was'nt working right the url was null
Tomasm21
Tomasm21OP3mo ago
yea
straightface
straightface3mo ago
now you can just add spring back fix url issue
Tomasm21
Tomasm21OP3mo ago
you mea @SpringBootTest?
straightface
straightface3mo ago
yeah
Tomasm21
Tomasm21OP3mo ago
ok.. hold on
straightface
straightface3mo ago
Stack Overflow
Populating Spring @Value during Unit Test
I'm trying to write a Unit Test for a simple bean that's used in my program to validate forms. The bean is annotated with @Component and has a class variable that is initialized using @Value("${t...
Tomasm21
Tomasm21OP3mo ago
No description
Tomasm21
Tomasm21OP3mo ago
Thank you, buddy.
straightface
straightface3mo ago
you're welcome
JavaBot
JavaBot3mo ago
Post Closed
This post has been closed by <@312509109863710732>.
Want results from more Discord servers?
Add your server