How to create unit tests for methods annotated with #Circuitbreaker - java

I implemented resilience4j in my project using the Spring Boot2 starter (https://resilience4j.readme.io/docs/getting-started-3).
I annotated a method with #CircuitBreaker that uses http client for calling an external service and the circuit breaker is working fine - including its fallback.
I'd like to add unit tests for it but when I run a test trying to simulate the fallback, nothing happens - the exception is thrown but is not handled by the circuit breaker mechanism.
I've found some examples using its metrics but it is not useful in my case.
Any thoughts?
Here is a snippet of my client:
#CircuitBreaker(name = "MY_CICUIT_BREAKER", fallbackMethod = "fallback")
public ResponseEntity<String> search(String value) {
ResponseEntity<String> responseEntity = restTemplate.exchange(
searchURL,
HttpMethod.GET,
new HttpEntity(new HttpHeaders()),
String.class,
value);
}
public ResponseEntity<String> fallback(String value, ResourceAccessException ex) {
return "fallback executed";
}

As andres and pvpkiran mentioned/explained, I had to add a integration test.
You can achieve that basically adding #SpringBootTest annotation to your test class, it will bootstrap a container with spring context on it.
I also autowired CircuitBreakerRegistry in order to reset the circuit breaker before each test so I could guarantee a clean test. For mocking/spying/verifying I used Mockito from spring boot test starter (spring-boot-starter-test).
Here is how I managed to test the fallbacks methods:
#ExtendWith(SpringExtension.class)
#SpringBootTest(classes = Application.class)
public class RestClientIntegrationTest {
private final String SEARCH_VALUE = "1234567890";
#MockBean( name = "myRealRestTemplateName")
private RestTemplate restTemplate;
#SpyBean
private MyRestClient client;
#Autowired
private CircuitBreakerRegistry circuitBreakerRegistry;
#BeforeEach
public void setUp() {
circuitBreakerRegistry.circuitBreaker("MY_CIRCUIT_BREAKER_NAME").reset();
}
#Test
public void should_search_and_fallback_when_ResourceAccessException_is_thrown() {
// prepare
when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(String.class), eq(SEARCH_VALUE)))
.thenThrow(ResourceAccessException.class);
String expectedResult = "expected result when fallback is called";
// action
String actualResult = client.search(SEARCH_VALUE);
// assertion
verify(client).fallback(eq(SEARCH_VALUE), any(ResourceAccessException.class));
assertThat(actualResult, is(expectedResult));
}
}
I hope there is no compilation error since I had to remove some non-relevant stuff.

You shouldn't test #CircuitBreaker in a unit test as it involves more than one class. Rather use an integration test.

Related

Spring Boot Test : Mix up #MockBean and #SpyBean in same Test class on same Bean object?

Here a test code sample with Spring Boot Test:
#SpringBootTest
#AutoConfigureMockMvc
class SendMoneyControllerSpringBootSpyBeanTest {
#Autowired
private MockMvc mockMvc;
#SpyBean
private SendMoneyUseCase sendMoneyUseCase;
#Test
void testSendMoneyWithMock() {
...
}
#Test
void testSendMoneyWithSpy() {
...
}
}
Now suppose the two test methods like in the snippet above. One is using the spy version of the spring bean, whereas the other is using a mock version of the spring bean. How can I mix up both and distinguish them in my test methods ?
For example, can I do :
#SpringBootTest
#AutoConfigureMockMvc
class SendMoneyControllerSpringBootSpyBeanTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private SendMoneyUseCase sendMoneyUseCaseMocked;
#SpyBean
private SendMoneyUseCase sendMoneyUseCaseSpied;
}
I know that in spring bean container, there is only one of sendMoneyUseCaseMocked or sendMoneyUseCaseSpied because they are the same java type. I can use a qualifier, to refer them by name. But in that case, how do I write my mock condition in the corresponding test method (write either mock condition on the mocked bean or the spied condition on the spied bean in the concerned test method).
EDIT : Another approach is to remove the line of code #MockBean, like this, the spied method is working. Consequently, I need then to programmatically code #MockBean in the mocked test method with Spring boot API, but how to do ?.
Thx.
I see two solutions.
Either use two test classes. One with the #MockBean object and one with the #SpyBean object. Both can inherit from the same abstract parent-class.
Let Spring Boot inject #MockBean and then replace it manually in the testSendMoneyWithSpy() test with the #SpyBean object using reflection.
But, why do you want to use the spy-object at all?
If you make unit-tests, you should mock the service and only test the controller here. And test the SendMoneyUseCase class in the SendMondeyUseCaseTest test.
(btw. strange name SendMondeyUseCase why not SendMoneyService or SendMoneyComponent. Or MoneySendService?)
Here the solution, first the solution code (my real test case, the one in first topic is more like a study code) :
#Slf4j
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class DocumentsApiTest extends ProductAPITestRoot {
#Autowired
private TestRestTemplate restTemplate;
#SpyBean
private AlfrescoService alfrescoServiceSpy;
#MockBean
private CloseableHttpClient closeableHttpClient;
#Test
public void testUploadDocument_SUCCESS() {
HttpHeaders headers = createOKHttpHeaders();
DocumentWithFile documentWithFile = createDocumentWithFile();
doReturn(StringUtils.EMPTY).when(alfrescoServiceSpy).sendDocument(anyString(), any(InputStream.class), eq(documentWithFile.getNomFichier()));
HttpEntity<DocumentWithFile> request = new HttpEntity<>(documentWithFile, headers);
ResponseEntity<Long> response = restTemplate.exchange(
"/documents/upload", HttpMethod.POST, request, Long.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).isEqualTo(1L);
}
#Test
public void testUploadDocument_500_INTERNAL_SERVER_ERROR() {
HttpHeaders headers = createOKHttpHeaders();
DocumentWithFile documentWithFile = createDocumentWithFile();
doThrow(new AlfrescoServiceException("Alfresco has failed !")).when(alfrescoServiceSpy).sendDocument(anyString(), any(InputStream.class), eq(documentWithFile.getNomFichier()));
HttpEntity<DocumentWithFile> request = new HttpEntity<>(documentWithFile, headers);
ResponseEntity<String> response = restTemplate.exchange(
"/documents/upload", HttpMethod.POST, request, String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
assertThat(response.getBody()).contains("Internal Server Error");
}
#Test
public void testUploadDocument_502_BAD_GATEWAY() throws IOException {
HttpHeaders headers = createOKHttpHeaders();
DocumentWithFile documentWithFile = createDocumentWithFile();
CloseableHttpResponse alfrescoResponse = mock(CloseableHttpResponse.class);
when(closeableHttpClient.execute(any(HttpPost.class))).thenReturn(alfrescoResponse);
when(alfrescoResponse.getStatusLine()).thenReturn(new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.BAD_GATEWAY.value(), "FINE!"));
HttpEntity<DocumentWithFile> request = new HttpEntity<>(documentWithFile, headers);
ResponseEntity<String> response = restTemplate.exchange(
"/documents/upload", HttpMethod.POST, request, String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_GATEWAY);
assertThat(response.getBody()).contains("Erreur Alfresco");
}
private static HttpHeaders createOKHttpHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + OK_TOKEN);
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
private static DocumentWithFile createDocumentWithFile() {
String fileAsString = RandomStringUtils.randomAlphabetic((int) 1e6);
byte[] fileAsStringBase64 = Base64.getEncoder().encode(fileAsString.getBytes());
DocumentWithFile documentWithFile = new DocumentWithFile();
String nomFichierExpected = "nomFichier.pdf";
documentWithFile
.id(8L)
.idCatalogue("idCatalogue")
.nom("nom")
.reference("reference")
.version("version")
.type(TypeDocument.IPID)
.fichier(new String(fileAsStringBase64))
.nomFichier(nomFichierExpected);
return documentWithFile;
}
}
If you look carrefully, the right way to mixup both : a mock and a spy of the same bean.
You can use #MockBean....and you use the spy version of this #MockBean with when(...).thenCallRealMethod(). But the REAL drawback of this is that if the #MockBean bean contains #Value field injection, thus they are NOT initialized. Meaning that #MockBean annotation set #Value fields of the mocked bean to null.
So I went for solution 2) because I need injection of #Value fileds.
Instead of #MockBean use #SpyBean of the concerned spring bean. Like this, you've got now the real bean. The question is how do I use it like a #MockBean. So to use a #SpyBean like a #MockBean, you needs to force the returned value of your #SpyBean bean like this for example :
doReturn(StringUtils.EMPTY).when(alfrescoServiceSpy).sendDocument(anyString(), any(InputStream.class), eq(documentWithFile.getNomFichier()));
As you can see, although alfrescoServiceSpy call the real code (not a mock), then you still can change its default behavior (calling the real code) with the mocked behavior like the snipped code above as example.
So test methods that need the mock version of #SpyBean declare an instruction of mocked behavior to do. And test methods that needs real code they don't do anything and #Value will be injected into the bean annotated #SpyBean the right way.
I'am personnaly satisfied of this code version.
Thanks you very much all.

Spring Boot Integration Testing - Mocking #Service before Application Context Starts?

I have to create a integration test for a microservice X which downloads, processes and importing csv files from external sftp servers. The whole process is started by a spring boot scheduler task which starts a spring batch job for processing and importing the data. The import process is done by the spring batch writer, which is a restTemplate Repository (so it calls post requests to another microservice Y).
I already managed to mock the sftp server, putting a test file on it and the current integration test is downloading the file. (https://github.com/stefanbirkner/fake-sftp-server-rule/)
My problem is, that the task will be scheduled immediately when the application context starts so there is no trigger like a api call. To get the whole integration test working i have to mock the part where the external microservice Y is called through a restTemplate call. This repository is called in the spring batch writer and this repository is created by a repositoryFactory which is a #Service. The repositoryFactory is injected in the spring batch configuration class.
I already tried to use the #MockBean annotation in the test class as well as in a separate test configuration where i am mocking the create() function of the factory to deliver a repository mock. But at some point it does not work and it delivers still the original object which leads to interupt the import job.
I also tried to use the WireMock library, but also in this case it does not catched any api calls and at some point leads to interrupt the sftp socket. (?)
I hope someone could help me out.
The current test:
#NoArgsConstructor
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#ContextConfiguration(classes = {JsonHalConfig.class})
#TestPropertySource(locations = "classpath:application-test.properties")
#TestMethodOrder(MethodOrderer.MethodName.class)
public class ImportIT {
#ClassRule
public static final FakeSftpServerRule sftpServer = new FakeSftpServerRule();
private static final String PASSWORD = "password";
private static final String USER = "username";
private static final int PORT = 14022;
#BeforeClass
public static void beforeClass() throws IOException {
URL resource = getTestResource();
if (resource != null) {
sftpServer.setPort(PORT).addUser(USER, PASSWORD);
sftpServer.createDirectories("/home/username/it-space/IMPORT", "/home/username/it-space/EXPORT");
sftpServer.putFile("/home/username/it-space/IMPORT/INBOX/testFile.csv",
resource.openStream());
} else {
throw new IOException("Failed to get test resources");
}
}
private static URL getTestResource() {
return ImportIT.class.getClassLoader().getResource("testFile.csv");
}
#Test
public void test_A_() throws IOException, RepositoryException {
assertTrue(true);
}
}
I tried following configuration classes
(included in #ContextConfiguration)
#Configuration/#TestConfiguration
public class RepositoryTestConfig {
#Bean
#Primary
public IRepositoryFactory repositoryFactory() {
IRepositoryFactory repositoryFactory = mock(IRepositoryFactory.class);
IRepository repository = mock(IRepository.class);
when(repositoryFactory.create(anyString())).thenReturn(repository);
return repositoryFactory;
}
}
(as static class in the test class)
#TestConfiguration/#Configuration
public static class RepositoryTestConfig {
#MockBean
private IRepositoryFactory repositoryFactory;
#PostConstruct
public void initMock(){
IRepository repository = mock(IRepository.class);
Mockito.when(repositoryFactory.create(anyString())).thenReturn(
repository
);
}
}
UPDATE 27.08.2021
I have a RestConfig #Component where a new RestTemplateBuilder is created. I tried to #MockBean this component to deliver a RestTemplateBuilder Mock and injected a MockRestServiceServer object to catch outgoing api calls. But unfortunately it does not work as aspected. Am i missing something? I also tried to create a "TestRestController" to trigger the scheduling of the task but it never delivers the mock...
I normally use #MockBean directly inside my test classes and inject the dedicated (but mocked) repository directly there and not create it inside the test configuration. I also add the test configuration class by #ContextConfiguration so it is loaded in current test context.
Inside my tests I am just using mockito the standard way and prepare the mocked parts as wanted for the dedicated test method.
Here an example snippet:
// ... do some imports ...
#RunWith(SpringRunner.class)
#ContextConfiguration(classes= {XYZSomeWantedClazz.class, DemoXYZMockTest.SimpleTestConfiguration.class})
#ActiveProfiles({Profiles.TEST})
public class DemoXYZMockTest {
//...
#MockBean
private DemoRepository mockedDemoRepository;
// ...
#Test
public void testMethodName() throws Exception{
/* prepare */
List<WantedEntityClazz> list = new ArrayList<>();
// add your wanted data to your list
// apply to mockito:
when(mockedDemoRepository.findAll()).thenReturn(list);
/* execute */
// ... execute the part you want to test...
/* test */
// ... test the results after execution ...
}
#TestConfiguration
#Profile(Profiles.TEST)
#EnableAutoConfiguration
public static class SimpleTestConfiguration{
// .. do stuff if necessary or just keep it empty
}
}
For a complete (old Junit4) working test example please take a look at:
https://github.com/mercedes-benz/sechub/blob/3f176a8f4c00b7e8577c9e3bea847ecfc91974c3/sechub-administration/src/test/java/com/daimler/sechub/domain/administration/signup/SignupAdministrationRestControllerMockTest.java

writing unit test cases for an interface which has methods without arguments

I have an interface which has a method without arguments
public interface HealthStatus {
Integer healthCheck();
}�
The implementation is as below
#Override
public Integer healthCheck() {
Integer status = 0;
try {
SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
if (proxyConfigProperties.getEnabled()) {
Proxy proxy = new Proxy(java.net.Proxy.Type.HTTP, new InetSocketAddress(proxyConfigProperties.getUrl(), proxyConfigProperties.getPort()));
simpleClientHttpRequestFactory.setProxy(proxy);
}
RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(simpleClientHttpRequestFactory));
ResponseEntity<String> healthResponse = restTemplate.exchange(eVerifyGovernmentProperties.getUrl(), HttpMethod.GET, null, String.class);
status = (healthResponse.getStatusCode() == HttpStatus.OK) ? 200 : 202;
} catch (Throwable th) {
th.printStackTrace();
}
return status;
}�
How can I unit test this method for positive scenarios and negative scenarios.
Edit:
I have refactored my class as below
#Service
#Qualifier("implementation")
public class HealthStatusImpl implements HealthStatus {
#Autowired
RestTemplateConfig restTemplateConfig;
#Autowired
private EVerifyGovernmentProperties eVerifyGovernmentProperties;
#Override
public Integer healthCheck() {
Integer status = 0;
try {
ResponseEntity<String> healthResponse = restTemplateConfig.getRestTemplate().exchange(eVerifyGovernmentProperties.getUrl(), HttpMethod.GET, null, String.class);
status = (healthResponse.getStatusCode() == HttpStatus.OK) ? 200 : 202;
} catch (Throwable th) {
th.printStackTrace();
}
return status;
}
}
Here is the class which instantiates the RestTemplate
#Component
public class RestTemplateConfig {
#Autowired
ProxyConfigProperties proxyConfigProperties;
public RestTemplate getRestTemplate(){
SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
if (proxyConfigProperties.getEnabled()) {
Proxy proxy = new Proxy(java.net.Proxy.Type.HTTP, new InetSocketAddress(proxyConfigProperties.getUrl(), proxyConfigProperties.getPort()));
simpleClientHttpRequestFactory.setProxy(proxy);
}
RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(simpleClientHttpRequestFactory));
return restTemplate;
}
}
Actually this is what you want to mock :
restTemplateConfig.getRestTemplate().exchange(eVerifyGovernmentProperties.getUrl(), HttpMethod.GET, null, String.class);
but this will require deep mocking and that is also a bad smell : you should not need to define such a statement to invoke the rest template. This responsibility should be defined in a specific class.
So move it into a method of a specific bean for example RestTemplateService that will relieve you from passing as many as parameters and it will also balance better responsibility of this class by reducing its dependencies :
ResponseEntity<String> healthResponse = restTemplateService.getForHealthCheck();
Now just mock it with Mockito.
Concerning RestTemplateService, you could create your own class or rely on Feign (here Spring Feign makes more sense) that enables declarative rest client via interface.
It would give :
public class HealthStatusImpl implements HealthStatus {
private RestTemplateService restTemplateService;
// favor constructor injection
public HealthStatusImpl(RestTemplateService restTemplateService){
this.restTemplateService = restTemplateService;
}
#Override
public Integer healthCheck() {
Integer status = 0;
try {
ResponseEntity<String> healthResponse = restTemplateService.getForHealthCheck();
status = healthResponse.getStatusCode().is2xxSuccessful() ? 200 : 400;
} catch (Throwable th) {
th.printStackTrace();
}
return status;
}
}
Note that Status.is2xxSuccessful() is generally better as it returns true for any successful response (200, 201, etc..). And if it is not successful you want to return an error response code.
From the unit test side, you should mock this dependency and record a mock behavior according to your scenarios.
Note that in your case, you don't want to load a whole spring context but you want to perform a plain unit test, that is without container. So don't use #SpringBootTest but only JUnit and Mockito.
For example with JUnit 5 :
#ExtendWith(MockitoExtension.class)
public class HealthStatusImplTest{
private HealthStatusImpl healthStatusImpl;
#Mock
private RestTemplateService restTemplateServiceMock;
#BeforeEach
public void beforeEach(){
healthStatusImpl = new HealthStatusImpl(restTemplateService);
}
#Test
public void healthCheck_when_200_is_returned(){
Mockito.when(restTemplateServiceMock)
.getForHealthCheck().thenReturn(new ResponseEntity(HttpStatus.OK));
assertEquals(200, healthStatusImpl.healthCheck());
}
#Test
public void healthCheck_when_200_is_not_returned(){
Mockito.when(restTemplateServiceMock)
.getForHealthCheck().thenReturn(new ResponseEntity(HttpStatus.NOT_FOUND));
assertEquals(400, healthStatusImpl.healthCheck());
}
}
Of course the RestTemplateService should also be unitary test and unitary tests don't relieve from writing integration tests for higher level components.
To unit test a web client such as a RestTemplate based class, you need a framework which mocks the server, e.g.
the one from Spring: MockRestServiceServer:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-client
https://www.baeldung.com/spring-mock-rest-template
WireMock: http://wiremock.org/docs/getting-started/
I'm not sure that your check (healthResponse.getStatusCode() == HttpStatus.OK) is correct, because if a status is not 2xx RestTemplate throws HttpStatusCodeException.
That's why it's always better to have some mocks if you integrate with a third party side.
That's why I also recommend you to consider MockRestServiceServer in your tests. see #Puce answer for links.
Also, there is no necessity to create a new RestTemplate for each request.
That's why I also recommend you to consider constructor injection. see #davidxxx answer for refactoring approaches. And don't forget to put connection timeouts in your RestTemplate settings.

Test RestTemplate Interceptors

i've implemented a Interceptors for RestTemplate (RestTemplateInterceptor.class):
#Autowired
private RestConfigurations configurations;
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.additionalInterceptors((ClientHttpRequestInterceptor) (httpRequest, bytes, clientHttpRequestExecution) -> {
HttpHeaders headers = httpRequest.getHeaders();
headers.add("X-API-KEY", configurations.getApiKey());
return clientHttpRequestExecution.execute(httpRequest,bytes);
}).build();
}
Now I want to test it. :)
One try looks like that:
#ExtendWith(SpringExtension.class)
#RestClientTest({RestTemplateInterceptor.class, RestConfigurations.class})
#AutoConfigureMockMvc
#SpringBootTest
class MyTestClass {
public static final String URL = "http://testMe.com/";
#Autowired
MockRestServiceServer mockServer;
#Autowired
RestTemplateBuilder restTemplateBuilder;
#Test
#DisplayName("Should include header X-API-KEY")
void headerShouldContainsXApiKey() throws Exception {
mockServer.expect(requestTo(URL)).andRespond(withSuccess("Hello world", TEXT_PLAIN));
String body = restTemplateBuilder.build().exchange(URL//
, GET, //
null, //
String.class).getBody();
assertThat(body).isEqualTo("Hello world");
mockServer.expect(header("X-API-KEY", ""));
}
But i failed with:
java.lang.AssertionError: No further requests expected: HTTP GET http://test.hornbach.de/
0 request(s) executed.
Anyone a hint? Thanks
If you check the Javadoc, you'll see that when you call additionalInterceptors, you're not modifying the existing builder instance but instead getting a new builder with a slightly different configuration. When you then call restTemplateBuilder.build() in your test case, you're building a template that has the unmodified configuration.
The ideal way to test something like this is to do so directly on the interceptor instance itself, but if you're wanting to perform a functional test by calling through to a mock server, you should inject the completed RestTemplate instance into your test case.

junit test case for spring MVC

we are developing an application using spring mvc framework. I have given all the classes below, please suggest how to write a junit test case for the below scenario.
I want to write a junit test case for the validateAccountInformation(requestDTO) method which is called in validateAccount(..) method of LPAValidator.java class. Below is my junit test case followed by the java classes. Actual call goes from the LPAController.java as shown in the below code.
LPAControllerTest.java
#Test(groups = "manual")
public void submitRequestForLPAAccountTest()
{
// businessCalendar.nextBusinessDay(
// LocalDateHelper.today(), LPAConstants.TWENTY_BUSSINESS_DAYS)
//i want to write the test case for the above commented logic,
//if business days is not equal to twenty days, test should fail.
}
LPAController.java
#RequestMapping(value = "/lpa/{accNumber}/spread, method = RequestMethod.GET)
public #ResponseBody LPAResponseDTO accountSearch(#RequestBody final LPARequestDTO clientrequestBody,
#PathVariable final String accNumber, final HttpServletResponse response)
{
//some logic goes here
final LPAAccountResponse domainResponse = service.submitRequestForLPAAccount(requestBody);
}
LPAServiceImpl.java
#PermitAll
#NonTransactional
public LPAResponse submitRequestForLPAAccount(final LPARequest requestDTO)
{
return lpaRepository.submitRequestForLPAAccount(requestDTO));
}
LPARepository.java
#PermitAll
#NonTransactional
public LPAResponse submitRequestForLPAAccount(final LPARequest requestDTO)
{
//some logic
lpaValidator.validateAccount(requestDTO);
//some logic
}
LPAValidator.java -- java class for validations
#component
class LPAValidator{
#Inject
private BusinessCalendar businessCalendar;
void validateAccount(final LPARequest requestDTO) throws Exception {
try {
validateAccountInformation(requestDTO);
} catch(Exception e){
}
}
private void validateAccountInformation(final LPARequest requestDTO) throws Exception{
final accDate lpaAccDate = requestDTO.getLPADate();
final LocalDate twentyBussinessDays = businessCalendar.nextBusinessDay(
LocalDateHelper.today(), LPAConstants.TWENTY_BUSSINESS_DAYS); //i want to write
//test case for this line of code, if business days given is more than twenty test should fail.
//some logic here
}
Please suggest what needs to be added in LPAControllerTest.java to test the nextBusinessDay(..) as discussed above.
You're trying to write an integration test in which your controller is called, which then calls all the subclasses until the validator is triggered. That is not a traditional 'unit test'.
A traditional unit test would just test the validator straight up, and nothing more.
Nevertheless, when writing an integration test, spring documentation to the rescue
In short, it'll require you to create an applicationcontext with all the necessary scaffolding, and then use a mockMvc call to do a GET on the created application.
If you want to test the validator, use simple mocking framework:
See [http://mockito.org]
Gives you something like this:
#Mock BusinessCalendar businessCalendarMock;
#Mock LPARequest mockRequest;
#Mock accDate mockDate;
#Mock LocalDate mockLocalDate;
#InjectMocks LPAValidator lpaValidator = new LPAValidator();
#Test public void testValidateAccount() {
when(mockRequest.getLPAdate()).thenReturn(mockDate);
when(businessCalendar.nextBusinessDay(LocalDateHelper.today(),LPAConstants.TWENTY_BUSSINESS_DAYS).thenReturn(mockLocalDate);
// continue your test from here
lpaValidator.validateAccount( mockRequest);
verify(businessCalendar).nextBusinessDay(LocalDateHelper.today(),LPAConstants.TWENTY_BUSSINESS_DAYS);
// although if the use of mockLocalDate is integral to your code, it'll probably show before and no verify is necessary;

Categories

Resources