-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enhance Unit Test Coverage for Skills and endorsement API Methods #166
Open
raj1802
wants to merge
5
commits into
Real-Dev-Squad:develop
Choose a base branch
from
raj1802:unit-tests
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+344
−0
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
1cb8a26
added unit tests for get and create skills methods
raj1802 cd2a2ed
unit tests addition
raj1802 cec5765
Merge branch 'develop' into unit-tests
yesyash 73d1e22
Fix formatting issues in unitTests
raj1802 290a01f
Merge branch 'unit-tests' of https://github.com/raj1802/skill-tree-ba…
raj1802 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
85 changes: 85 additions & 0 deletions
85
skill-tree/src/test/java/com/RDS/skilltree/unitTests/EndorsementsApiUnitTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package com.RDS.skilltree.unitTests; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.mockito.Mockito.when; | ||
|
||
import com.RDS.skilltree.dtos.RdsGetUserDetailsResDto; | ||
import com.RDS.skilltree.models.Endorsement; | ||
import com.RDS.skilltree.models.Skill; | ||
import com.RDS.skilltree.repositories.EndorsementRepository; | ||
import com.RDS.skilltree.services.EndorsementServiceImplementation; | ||
import com.RDS.skilltree.services.external.RdsService; | ||
import com.RDS.skilltree.viewmodels.EndorsementViewModel; | ||
import com.RDS.skilltree.viewmodels.RdsUserViewModel; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.mockito.InjectMocks; | ||
import org.mockito.Mock; | ||
import org.mockito.MockitoAnnotations; | ||
|
||
public class EndorsementsApiUnitTests { | ||
|
||
@Mock private EndorsementRepository endorsementRepository; | ||
|
||
@Mock private RdsService rdsService; | ||
|
||
@InjectMocks private EndorsementServiceImplementation endorsementService; | ||
|
||
@BeforeEach | ||
public void setup() { | ||
MockitoAnnotations.openMocks(this); // Initialize mocks | ||
} | ||
|
||
@Test | ||
@DisplayName("To test getAllEndorsementsBySkillId() method") | ||
public void testGetAllEndorsementsBySkillId() { | ||
List<Endorsement> endorsements = new ArrayList<>(); | ||
|
||
Integer skillId = 1; | ||
|
||
// initializing a skill | ||
Skill skill1 = new Skill(); | ||
skill1.setId(skillId); | ||
skill1.setName("python"); | ||
|
||
// initializing an endorsement | ||
Endorsement endorsement1 = new Endorsement(); | ||
endorsement1.setId(1); | ||
endorsement1.setSkill(skill1); | ||
endorsement1.setEndorserId("456"); | ||
endorsement1.setEndorseId("123"); | ||
endorsement1.setMessage("Please approve my endorsement for this skill"); | ||
|
||
endorsements.add(endorsement1); | ||
|
||
RdsGetUserDetailsResDto rdsGetUserDetailsResDto1 = new RdsGetUserDetailsResDto(); | ||
RdsUserViewModel rdsUserViewModel1 = new RdsUserViewModel(); | ||
rdsUserViewModel1.setId("123"); | ||
rdsGetUserDetailsResDto1.setUser(rdsUserViewModel1); | ||
|
||
RdsGetUserDetailsResDto rdsGetUserDetailsResDto2 = new RdsGetUserDetailsResDto(); | ||
RdsUserViewModel rdsUserViewModel2 = new RdsUserViewModel(); | ||
rdsUserViewModel2.setId("456"); | ||
rdsGetUserDetailsResDto2.setUser(rdsUserViewModel2); | ||
|
||
// Mock behaviour | ||
when(endorsementRepository.findBySkillId(skillId)).thenReturn(endorsements); | ||
when(rdsService.getUserDetails(endorsement1.getEndorseId())) | ||
.thenReturn(rdsGetUserDetailsResDto1); | ||
when(rdsService.getUserDetails(endorsement1.getEndorserId())) | ||
.thenReturn(rdsGetUserDetailsResDto2); | ||
|
||
// Act | ||
|
||
List<EndorsementViewModel> endorsmentsBySkillId = | ||
endorsementService.getAllEndorsementsBySkillId(skillId); | ||
|
||
assert (endorsmentsBySkillId.size() == 1); | ||
assertEquals("456", endorsmentsBySkillId.get(0).getEndorser().getId()); | ||
assertEquals("123", endorsmentsBySkillId.get(0).getEndorse().getId()); | ||
assertEquals("python", endorsmentsBySkillId.get(0).getSkill().getName()); | ||
} | ||
} |
259 changes: 259 additions & 0 deletions
259
skill-tree/src/test/java/com/RDS/skilltree/unitTests/SkillsApiUnitTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,259 @@ | ||
package com.RDS.skilltree.unitTests; | ||
|
||
import static org.junit.jupiter.api.Assertions.*; | ||
import static org.mockito.Mockito.*; | ||
|
||
import com.RDS.skilltree.dtos.RdsGetUserDetailsResDto; | ||
import com.RDS.skilltree.enums.SkillTypeEnum; | ||
import com.RDS.skilltree.enums.UserRoleEnum; | ||
import com.RDS.skilltree.enums.UserSkillStatusEnum; | ||
import com.RDS.skilltree.exceptions.NoEntityException; | ||
import com.RDS.skilltree.exceptions.SkillAlreadyExistsException; | ||
import com.RDS.skilltree.models.JwtUser; | ||
import com.RDS.skilltree.models.Skill; | ||
import com.RDS.skilltree.models.UserSkills; | ||
import com.RDS.skilltree.repositories.SkillRepository; | ||
import com.RDS.skilltree.repositories.UserSkillRepository; | ||
import com.RDS.skilltree.services.SkillServiceImplementation; | ||
import com.RDS.skilltree.services.external.RdsService; | ||
import com.RDS.skilltree.utils.GenericResponse; | ||
import com.RDS.skilltree.viewmodels.CreateSkillViewModel; | ||
import com.RDS.skilltree.viewmodels.RdsUserViewModel; | ||
import com.RDS.skilltree.viewmodels.SkillRequestsWithUserDetailsViewModel; | ||
import com.RDS.skilltree.viewmodels.SkillViewModel; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.mockito.InjectMocks; | ||
import org.mockito.Mock; | ||
import org.mockito.MockitoAnnotations; | ||
import org.springframework.security.core.Authentication; | ||
import org.springframework.security.core.context.SecurityContext; | ||
import org.springframework.security.core.context.SecurityContextHolder; | ||
|
||
public class SkillsApiUnitTests { | ||
|
||
@Mock private SkillRepository skillRepository; | ||
|
||
@Mock private UserSkillRepository userSkillRepository; | ||
|
||
@Mock private RdsService rdsService; | ||
|
||
@Mock private Authentication authentication; | ||
|
||
@Mock private SkillRequestsWithUserDetailsViewModel skillRequestsWithUserDetailsViewModel; | ||
|
||
@InjectMocks | ||
private SkillServiceImplementation skillService; // Class containing the getAll() method | ||
|
||
@BeforeEach | ||
public void setup() { | ||
MockitoAnnotations.openMocks(this); // Initialize mocks | ||
|
||
SecurityContext securityContext = mock(SecurityContext.class); | ||
SecurityContextHolder.setContext(securityContext); | ||
when(securityContext.getAuthentication()).thenReturn(authentication); | ||
} | ||
|
||
@Test | ||
@DisplayName( | ||
"Test the getAll() method returns all the created skills, where the skills return in a sorted order based on skill-Id.") | ||
public void getAllSkillsHappyFlow() { | ||
|
||
Skill skill1 = new Skill(); | ||
skill1.setId(1); | ||
skill1.setName("Java"); | ||
skill1.setType(SkillTypeEnum.ATOMIC); | ||
|
||
Skill skill2 = new Skill(); | ||
skill2.setId(2); | ||
skill2.setName("Spring Boot"); | ||
skill2.setType(SkillTypeEnum.ATOMIC); | ||
|
||
// Mock the repository's behavior | ||
when(skillRepository.findAll()).thenReturn(Arrays.asList(skill1, skill2)); | ||
|
||
// Act: Call the method to be tested | ||
List<SkillViewModel> result = skillService.getAll(); | ||
|
||
// Assert: Verify the result | ||
assertEquals(2, result.size()); | ||
assertEquals("Java", result.get(0).getName()); | ||
assertEquals("Spring Boot", result.get(1).getName()); | ||
|
||
// Verify that the repository was called once | ||
verify(skillRepository, times(1)).findAll(); | ||
} | ||
|
||
@Test | ||
@DisplayName("Test the create() skill method, which returns the created skill data") | ||
public void testCreateSkill_Success() { | ||
// Arrange: Mock request and setup mocks | ||
CreateSkillViewModel createSkill = new CreateSkillViewModel(); | ||
createSkill.setName("python"); | ||
createSkill.setType(SkillTypeEnum.ATOMIC); | ||
|
||
// Mock JwtUser with rdsUserId and role | ||
JwtUser jwtUser = new JwtUser("123", UserRoleEnum.USER); | ||
|
||
RdsUserViewModel viewModel = new RdsUserViewModel(); | ||
viewModel.setId("123"); | ||
|
||
RdsGetUserDetailsResDto userDetails = new RdsGetUserDetailsResDto(); | ||
userDetails.setUser(viewModel); | ||
|
||
Skill skillEntity = new Skill(); | ||
skillEntity.setId(5); | ||
skillEntity.setName("python"); | ||
skillEntity.setType(SkillTypeEnum.ATOMIC); | ||
skillEntity.setCreatedBy(userDetails.getUser().getId()); | ||
|
||
SkillViewModel expectedViewModel = SkillViewModel.toViewModel(skillEntity); | ||
|
||
// Mock behavior | ||
|
||
when(authentication.getPrincipal()).thenReturn(jwtUser); // Return mock JwtUser | ||
when(rdsService.getUserDetails(jwtUser.getRdsUserId())) | ||
.thenReturn(userDetails); // Use rdsUserId | ||
when(skillRepository.saveAndFlush(any(Skill.class))).thenReturn(skillEntity); | ||
|
||
when(skillRepository.existsByName("python")).thenReturn(false); | ||
|
||
// Act: Call the method | ||
SkillViewModel actualViewModel = skillService.create(createSkill); | ||
|
||
// Assert: Verify the result | ||
assertNotNull(actualViewModel); | ||
assertEquals(expectedViewModel.getId(), actualViewModel.getId()); | ||
assertEquals(expectedViewModel.getName(), actualViewModel.getName()); | ||
assertEquals(expectedViewModel.getType(), actualViewModel.getType()); | ||
|
||
// Verify that the repository and service were called correctly | ||
verify(skillRepository, times(1)).existsByName("python"); | ||
verify(skillRepository, times(1)).saveAndFlush(any(Skill.class)); | ||
} | ||
|
||
@Test | ||
@DisplayName("Test the create() skill method, when an already present skill is being added") | ||
public void testCreateSkill_AlreadyExists() { | ||
// Arrange | ||
CreateSkillViewModel createSkill = new CreateSkillViewModel(); | ||
createSkill.setName("python"); | ||
createSkill.setType(SkillTypeEnum.ATOMIC); | ||
|
||
// Mock behavior | ||
when(skillRepository.existsByName("python")).thenReturn(true); | ||
|
||
// Act & Assert: Verify that exception is thrown | ||
SkillAlreadyExistsException exception = | ||
assertThrows( | ||
SkillAlreadyExistsException.class, | ||
() -> skillService.create(createSkill), | ||
"Skill with name " + createSkill.getName() + "already exists"); | ||
|
||
assertEquals("Skill with name python already exists", exception.getMessage()); | ||
|
||
// Verify repository was called once, but saveAndFlush wasn't called | ||
verify(skillRepository, times(1)).existsByName("python"); | ||
verify(skillRepository, never()).saveAndFlush(any(Skill.class)); | ||
} | ||
|
||
// To be modified | ||
|
||
@Test | ||
@DisplayName("To Test the approveRejectSkillRequest() method, when action is approved") | ||
public void testApproveRejectSkillRequest() { | ||
|
||
// Arrange | ||
Integer skillId = 1; | ||
String endorseId = "123"; | ||
UserSkillStatusEnum action = UserSkillStatusEnum.APPROVED; | ||
|
||
Skill skill1 = new Skill(); | ||
skill1.setId(1); | ||
|
||
List<UserSkills> existingSkillRequest = new ArrayList<>(); | ||
UserSkills userSkill1 = new UserSkills(); | ||
userSkill1.setId("1"); | ||
userSkill1.setUserId("123"); | ||
userSkill1.setStatus(UserSkillStatusEnum.PENDING); | ||
userSkill1.setSkill(skill1); | ||
existingSkillRequest.add(userSkill1); | ||
|
||
when(userSkillRepository.findByUserIdAndSkillId(userSkill1.getUserId(), skill1.getId())) | ||
.thenReturn(existingSkillRequest); | ||
when(userSkillRepository.save(userSkill1)).thenReturn(userSkill1); | ||
|
||
// Act: Call the method | ||
GenericResponse<String> response = | ||
skillService.approveRejectSkillRequest(skillId, endorseId, action); | ||
|
||
// Assert | ||
assertNotNull(response); | ||
assertEquals("approved", response.getMessage()); // Depending on the action | ||
assertEquals(UserSkillStatusEnum.APPROVED, userSkill1.getStatus()); | ||
} | ||
|
||
@Test | ||
@DisplayName("To Test the approveRejectSkillRequest() method, when action is rejected") | ||
public void testApproveRejectSkillRequest_Reject() { | ||
// Arrange | ||
Integer skillId = 2; | ||
String endorseId = "456"; | ||
UserSkillStatusEnum action = UserSkillStatusEnum.REJECTED; | ||
|
||
Skill skill1 = new Skill(); | ||
skill1.setId(2); | ||
|
||
UserSkills mockSkillRequest = new UserSkills(); | ||
mockSkillRequest.setSkill(skill1); | ||
mockSkillRequest.setUserId(endorseId); | ||
mockSkillRequest.setStatus(UserSkillStatusEnum.PENDING); | ||
|
||
List<UserSkills> existingSkillRequest = new ArrayList<>(); | ||
existingSkillRequest.add(mockSkillRequest); | ||
|
||
// Mock repository behavior | ||
when(userSkillRepository.findByUserIdAndSkillId(endorseId, skillId)) | ||
.thenReturn(existingSkillRequest); | ||
when(userSkillRepository.save(mockSkillRequest)).thenReturn(mockSkillRequest); | ||
|
||
// Act | ||
GenericResponse<String> response = | ||
skillService.approveRejectSkillRequest(skillId, endorseId, action); | ||
|
||
// Assert | ||
assertNotNull(response); | ||
assertEquals("rejected", response.getMessage()); // Depending on the action | ||
assertEquals(UserSkillStatusEnum.REJECTED, mockSkillRequest.getStatus()); | ||
|
||
// Verify that the save method was called | ||
verify(userSkillRepository, times(1)).save(mockSkillRequest); | ||
} | ||
|
||
@Test | ||
@DisplayName("To Test the approveRejectSkillRequest() method, when no skill requests are present") | ||
public void testApproveRejectSkillRequest_NoEntityException() { | ||
// Arrange | ||
Integer skillId = 3; | ||
String endorseId = "789"; | ||
UserSkillStatusEnum action = UserSkillStatusEnum.APPROVED; | ||
|
||
// Mock repository behavior for no entity found | ||
when(userSkillRepository.findByUserIdAndSkillId(endorseId, skillId)) | ||
.thenReturn(new ArrayList<>()); | ||
|
||
// Act & Assert | ||
assertThrows( | ||
NoEntityException.class, | ||
() -> { | ||
skillService.approveRejectSkillRequest(skillId, endorseId, action); | ||
}); | ||
|
||
// Verify that the save method was never called | ||
verify(userSkillRepository, never()).save(any(UserSkills.class)); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we mocking the Db calls?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes Prakash, correct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we mocking the db calls?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As repository is a dependency for that method and we wanted to test in isolated space for unit tests, I have mocked it and provided pre defined data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @prakashchoudhary07 could you please let me know, for the above explanation regarding the reporsitory mocking, if any chnages needed please let me know
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case, if I don't have DB code, if queries are wrong also then tests will pass
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @prakashchoudhary07 so this part of db validation is being covered as part of integration testing, so should we include in unit tests as well. please let me know?
cc @yesyash
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I will still insist we do it.
Now I am not sure what the test is being written for here. Is it a unit or integration?
So if you were testing the class why are you invoicing the db?
And if some behavior changes, then also since things are mocked, will tests pass without any issues right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And if you are only writing unit tests for a module, why involve different modules here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@prakashchoudhary07
For the above question, for example, when writing unit tests for the skills API getAll() method, we are retrieving all the skills from the skill repository. So, the dependency for this method is the skillRepository class. To test the getAll method in isolation, I have mocked this class implementation.
Based on the above conversation, do you think? should we include DB code as well? if yes should we use an in-memory database, as if we include the real db, as the data will be dynamic we should think of any strategy for this? could you please advise.
cc @yesyash