junit test case for spring MVC - java

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;

Related

Java writing Spring Boot Unit Tests

I was wondering if I wrote this test in a proper way to mock a real situation. Can you please provide any feedback?
I'm using Mockito in a Spring Boot environment. I'm new to Mockito and other mocking techniques, but I want to know if I'm on the right path or not.
#RunWith(MockitoJUnitRunner.class)
#SpringBootTest
class FileServiceImplTest {
#Mock
private UserPrincipal userPrincipal;
#Mock
private User user;
#Mock
private FileService fileService;
#BeforeEach
void initialize() {
user = new User("testUser", "test#email.com", "testPassword");
user.setId(1L);
user.setRoles(List.of(Role.User));
userPrincipal = UserPrincipal.create(user);
}
#Test
void usedMockUpsShouldNotBeNull() {
assertAll("All mock instaces of classes should not be null",
() -> assertNotNull(fileService),
() -> assertNotNull(userPrincipal),
() -> assertNotNull(user)
);
}
#Test
void collectionOfFilesShouldChangeAfterNewFileIsAdded_Mockito() throws ExecutionException, InterruptedException {
Image image = createImageFile();
List<? super File> files = createFilesCollection();
doReturn(files).when(fileService).getAll(userPrincipal);
int initialSize = fileService.getAll(userPrincipal).size();
fileService.save(image);
doReturn(files.add(image)).when(fileService).save(image);
int newSize = fileService.getAll(userPrincipal).size();
assertNotEquals(newSize, initialSize);
Mockito.verify(fileService, atLeast(2)).getAll(userPrincipal);
Mockito.verify(fileService).save(image);
}
}
I am sorry that you are in the wrong path.
If FileService is just an interface, you do not need to test it.
If FileService is an implementation, you should create an actual instance to test it but not a mock.
The mock is only useful for the direct dependencies of the class that you are testing (i.e FileSerivice) such that you can easily stub the result when calling methods on these dependencies and verify if the class you are testing interacts with them correctly. (i.e. call the correct methods with the correct parameters etc.)
As I cannot see FileSerivice 's source codes , but if UserPrincipal and User are not its dependencies , it does not make sense to mock them.
Also as mentioned by other in the comment, as you are not doing the integration testing with some Spring framework stuff, you should simply rewrite your test as a plain Mockito test which is simpler and run faster :
#ExtendWith(MockitoExtension.class)
public class FileServiceImplTest {
}

NullPointerException while trying to test a Spring MVC controller method with JUnit, Mockito

I am trying to unit test a Spring MVC controller method, but my unit test keeps failing.
I have a Spring MVC controller method:
// MyController.java
#RequestMapping(value = "/end-point", method = RequestMethod.GET)
public ModelAndView getData(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
ModelAndView mv = new ModelAndView();
DataManager dataManager = DataManager.getInstance();
DataUser currentUser = (DataUser) request.getSession().getAttribute("currentUser");
List<DataItem> dataList = dataManager.getDataForUser(currentUser.getId());
mv.addObject("dataList", dataList);
mv.setViewName("home-page");
return mv;
}
I am trying to test this controller method with JUnit. I have very little experience unit testing and am trying to learn. Seems like this is near-impossible or does not make sense to do without a mocking library, and the project I'm working on already has Mockito as a dependency so I'm trying to use that. My test class is below:
//MyControllerTest.java
public class MyControllerTest {
#InjectMocks
private MyController myController;
#Mock
HttpServletRequest request;
#Mock
HttpServletResponse response;
#Mock
ModelAndView mockModelAndView;
#Mock
DataManager mockDataManager;
#Mock
DataUser mockDataUser;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void getDataTest() throws Exception {
//I guess I have to somehow mock mockDataUser here even more than #Mock???
Mockito.when(request.getSession().getAttribute("currentUser")).thenReturn(mockVendorUser); // <-- this is where the null pointer exception is coming from
Mockito.when(myController.getData(request, response)).thenReturn(mockModelAndView);
ModelAndView testing = profileControllerWH.getMySkus(request, response);
assertEquals(1, 1);
}
}
When I run my test, it fails and I get a java.lang.NullPointerException exception in the console, specifying the line above with the null pointer exception comment.
I have tried looking up how to mock classes with Mockito, and I keep seeing the #Mock annotation, which I already have as #Mock DataUser (as well as other classes I am using in the controller method that I guess I need to mock).
How do I get this to work? It seems like I have to create a whole new DataUser object with fake data, but then that seems to defeat the purpose of the mocking library. What would the point of using Mockito be if I have to create my own objects with fake data? Or, I might be misunderstanding this because of lack of experience.
Remember that by default, unstubbed methods return default value of return type when called (0 for numbers, null for Objects).
You haven't stubbed request.getSession() so it returns null.
You need to:
provide a mock for session
stub request.getSession() to return this mock
stub session.getAttribute("currentUser")
On top of that:
While calling the controller method in your test certainly has value of testing the method body, but you will test more functionality (like request and response serialization) if you re-implement your test as a #WebMvcTest

JUnit test for my method

Hello every one I need to write unit tests for my methods. I'm having a bit of trouble because I'm new to JUnit. I need to write a test for this method.
this is my method
#Override
public Long countSellingOrdersInQueue(String principal) {
List<String> states = Arrays.asList(PENDING.name(), REGULARIZED.name());
return orderRepository.countByArticleUserIdAndStateIn(principal, states);
}
I try but i'm blocked and this is my result
P.S. test is passed but I don't understand if my test is true
#MockBean
private OrderRepository orderRepository;
private String principal ;
#Test
public void countSellingOrdersInQueueTest(){
orderService.countSellingOrdersInQueue(principal);
List<String> states = Arrays.asList(PENDING.name(), REGULARIZED.name());
orderRepository.countByUserIdAndStateIn(principal,states);
}
In your case, it is just the unit test, you need not use #MockBean, as it loads the context. Unit tests are meant to be run faster, using #MockBean, will load the context and takes time to complete the test. Here is the suggestion of when to use #Mock and when to use #MockBean.
As Maxim said, there were no assertions in the test. That was the reason why the tests weren't failing.
Few things to keep in mind while writing the test.
Tests are considered as documentation for the code, it should be more readable in such a way it makes others to understand the code.
As said before, unit tests are for giving faster feedback
Have AAA (Arrange, Act, Assert) structure in tests. More info here
Here is the code:
public class OrderServiceTest {
#InjectMocks
private OrderService orderService;
#Mock
private OrderRepository orderRepository;
#Before
public void setUp() throws Exception {
initMocks(this);
}
#Test
public void countSellingOrdersInQueueTest(){
when(orderRepository.countByArticleUserIdAndStateIn(any(), any())).thenReturn(1L);
String principal = "dummyString";
Long actualCount = orderService.countSellingOrdersInQueue(principal);
List<String> expectedStates = Arrays.asList("State 1", "State 2");
assertThat(actualCount, is(1L));
verify(orderRepository).countByArticleUserIdAndStateIn(principal, expectedStates);
}
}
Test passes because you don't have any assertion, which checks result. You just invoke methods which executes without exception.
Simple test example:
#Test
public void test() {
assertEquals(true, true);
}
In your case test will be look likes:
#Test
public void countSellingOrdersInQueueTest(){
orderService.countSellingOrdersInQueue(principal);
List<String> states = Arrays.asList(PENDING.name(), REGULARIZED.name());
orderRepository.countByUserIdAndStateIn(principal,states);
assertEquals(10, orderRepository.countByUserIdAndStateIn(principal,states));//10 replace to expectetion count
//add some more checks
}

How to test business logic in method?

I have such method in my service layer:
public Long calculateItemsCostInShoppingCart(Long shoppingCartId) {
List<Item> items = shoppingCartRepository.findAllItems(shoppingCartId);
Long cost = 0L;
for (Item item : items) {
cost += item.getPrice();
}
return cost;
}
And I need to test calculation of summary cost of all items in list. I was thought about mockito, but it didn't work out cause mockito just create stubs, I need real entrance data and result based on them. How can do it?
// create mock
ShoppingRepository mock = mock(ShoppingRepository.class);
// define return value for method findAllItems()
when(mock.findAllItems()).thenReturn(listOf(...));
Here is an example how you can test it with Mockito:
public class SomeCalculatorTest {
#Mock
private ShoppingCartRepository shoppingCartRepository;
#InjectMocks
private SomeCalculator someCalculator = new SomeCalculator();
#Before
public void setUp() {
initMocks(this);
}
#Test
public void testEmptyItemsList() {
when(shoppingCartRepository.findAllItems(any())).thenReturn(new ArrayList<>());
final Long result = someCalculator.calculateItemsCostInShoppingCart(1L);
assertThat(result, is(0L));
}
#Test
public void testOneItemInList() {
when(shoppingCartRepository.findAllItems(any())).thenReturn(Arrays.asList(new ItemImpl(25L)));
final Long result = someCalculator.calculateItemsCostInShoppingCart(1L);
assertThat(result, is(25L));
}
#Test
public void testTwoItemInList() {
when(shoppingCartRepository.findAllItems(any())).thenReturn(Arrays.asList(new ItemImpl(25L), new ItemImpl(12L)));
final Long result = someCalculator.calculateItemsCostInShoppingCart(1L);
assertThat(result, is(37L));
}
}
Assuming that you are developing a Java web application which runs on a application server another option might be to use Arquillian (http://arquillian.org/). In a nutshell, Arquillian is a framework which allows you to test you logic in environment it will run. But it might be some work to integrate Arquillian into your project. We are using Arquillian in several projects and it works well so far. Even the Persistence module which is an Alpha version works well.
And I need to test calculation of summary cost of all items in list.
In this case, you have to isolate the shoppingCartRepository dependency that doesn't perform any calculation.
I need real entrance data and result based on them. How can do it?
It describes an integration test. In this case, don't use Mockito.
To unit test :
You have to mock the dependency and you also need a way to set it in the instance of the class under test.
A constructor is often a fine way (let calling the class under test MyService):
public MyService(ShoppingCartRepository shoppingCartRepository){
this.shoppingCartRepository = shoppingCartRepository;
}
Then, in the test you should mock ShoppingCartRepository, record a behavior for findAllItems() and pass the mock in the constructor of MyService.
#Mock
private ShoppingCartRepository shoppingCartRepositoryMock;
#Test
public void calculateItemsCostInShoppingCart(){
Long cartId = Long.valueOf(123);
// set the dependency
MyService myService = new MyService(shoppingCartRepositoryMock);
// create the mock
Mockito.when(shoppingCartRepositoryMock.findAllItems(cartId))
.thenReturn(createMockedItems());
//action
Long actualCost = myService.calculateItemsCostInShoppingCart(cartId);
// assertion
Assert.assertEquals(expectedCost, actualCost);
}
private List<Item> createMockedItems() { ... }
You can use Rest assured library for test
get Rest assured response Object, and call method for method object of list.
#BeforeClass
public static void init() {
RestAssured.baseURI = "http://localhost";
RestAssured.port = 8080;
}
#Test
public void testUserRegistration() {
Response response =
RestAssured
.given()
.get(URL_LOGIN)
.then()
.assertThat()
.statusCode(200);
Assert.assertThat(200, Matchers.is(200));
Assert.assertThat(response.getStatusCode(), Matchers.is(200));
}

how to unit test method using "Spring Data JPA" Specifications

I was playing with org.springframework.data.jpa.domain.Specifications, it's just a basic search :
public Optional<List<Article>> rechercheArticle(String code, String libelle) {
List<Article> result = null;
if(StringUtils.isNotEmpty(code) && StringUtils.isNotEmpty(libelle)){
result = articleRepository.findAll(Specifications.where(ArticleSpecifications.egaliteCode(code)).and(ArticleSpecifications.egaliteLibelle(libelle)));
}else{
if(StringUtils.isNotEmpty(code)){
result= articleRepository.findAll(Specifications.where(ArticleSpecifications.egaliteCode(code)));
}else{
result = articleRepository.findAll(Specifications.where(ArticleSpecifications.egaliteLibelle(libelle)));
}
}
if(result.isEmpty()){
return Optional.empty();
}else{
return Optional.of(result);
}
}
And that's actually working fine but I'd like to write unit tests for this method and I can't figure out how to check specifications passed to my articleRepository.findAll()
At the moment my unit test looks like :
#Test
public void rechercheArticle_okTousCriteres() throws FacturationServiceException {
String code = "code";
String libelle = "libelle";
List<Article> articles = new ArrayList<>();
Article a1 = new Article();
articles.add(a1);
Mockito.when(articleRepository.findAll(Mockito.any(Specifications.class))).thenReturn(articles);
Optional<List<Article>> result = articleManager.rechercheArticle(code, libelle);
Assert.assertTrue(result.isPresent());
//ArgumentCaptor<Specifications> argument = ArgumentCaptor.forClass(Specifications.class);
Mockito.verify(articleRepository).findAll(Specifications.where(ArticleSpecifications.egaliteCode(code)).and(ArticleSpecifications.egaliteLibelle(libelle)));
//argument.getValue().toPredicate(root, query, builder);
}
Any idea?
I was having almost the same problems as you had, and I changed my class that contains Specifications to be an object instead of just one class with static methods. This way I can easily mock it, use dependency injection to pass it, and test which methods were called (without using PowerMockito to mock static methods).
If you wanna do like I did, I recommend you to test the correctness of specifications with integration tests, and for the rest, just if the right method was called.
For example:
public class CdrSpecs {
public Specification<Cdr> calledBetween(LocalDateTime start, LocalDateTime end) {
return (root, query, cb) -> cb.between(root.get(Cdr_.callDate), start, end);
}
}
Then you have an integration test for this method, which will test whether the method is right or not:
#RunWith(SpringRunner.class)
#DataJpaTest
#Sql("/cdr-test-data.sql")
public class CdrIntegrationTest {
#Autowired
private CdrRepository cdrRepository;
private CdrSpecs specs = new CdrSpecs();
#Test
public void findByPeriod() throws Exception {
LocalDateTime today = LocalDateTime.now();
LocalDateTime firstDayOfMonth = today.with(TemporalAdjusters.firstDayOfMonth());
LocalDateTime lastDayOfMonth = today.with(TemporalAdjusters.lastDayOfMonth());
List<Cdr> cdrList = cdrRepository.findAll(specs.calledBetween(firstDayOfMonth, lastDayOfMonth));
assertThat(cdrList).isNotEmpty().hasSize(2);
}
And now when you wanna unit test other components, you can test like this, for example:
#RunWith(JUnit4.class)
public class CdrSearchServiceTest {
#Mock
private CdrSpecs specs;
#Mock
private CdrRepository repo;
private CdrSearchService searchService;
#Before
public void setUp() throws Exception {
initMocks(this);
searchService = new CdrSearchService(repo, specs);
}
#Test
public void testSearch() throws Exception {
// some code here that interact with searchService
verify(specs).calledBetween(any(LocalDateTime.class), any(LocalDateTime.class));
// and you can verify any other method of specs that should have been called
}
And of course, inside the Service you can still use the where and and static methods of Specifications class.
I hope this can help you.
If you are writing Unit Tests then you should probably mock the call to findAll() method of articleRepository Class using a mocking framework like Mockito or PowerMock.
There is a method verify() using which you can check if the mock is invoked for the particular parameters.
For Example, if you are mocking the findAll() method of articleRepository Class and want to know if this method is called with particular arguments then you can do something like:
Mokito.verify(mymock, Mockito.times(1)).findAll(/* Provide Arguments */);
This will fail the test if mock has not been called for the arguments that you provided.
Your problem is that you are doing too many things within that one method. You should have three different methods that work on articleRepository.
Then you can use mocking as the others suggest:
setup your mocks so that you know which call on articleRepository should be made
verify that exactly the expected calls are happening
Please note: these three methods should be internal; the main point there is: you can't test this method with ONE call from the outside; as it is doing more than one thing, depending on the input that you provide. Thus you need to create at least one test method for each of the potential paths in your code. And that becomes easier (from a conceptual point of view) when you separate your code into different methods.

Categories

Resources