I am trying to test my method for getting back all entities that exist in my db. I am using JUnit and Mockito. I have no experience with testing so far and this is how far I've got:
This is my method from the agency service to get back all entities, using the findAll() function of JpaRepository:
public List<AgencyDto> getAll() {
return repo.findAll().stream().map(agency -> mapper.mapToDto(agency)).collect(Collectors.toList());
}
#ExtendWith(MockitoExtension.class)
public class AgencyServiceTest {
#Mock
private AgencyRepository agencyRepository;
#InjectMocks
private AgencyService agencyService;
#Test
void getAgencies() {
List<Agency> existingAgencies = new ArrayList<Agency>();
Agency agency1 = new Agency();
Agency agency2 = new Agency();
existingAgencies.add(agency1);
existingAgencies.add(agency2);
when(agencyRepository.findAll()).thenReturn(existingAgencies);
List<AgencyDto> result = agencyService.getAll();
assertEquals(existingAgencies, result);
}
}
When running the test, the value for expected seems ok, but the value for actual is an empty array:
Expected :[com.project.DTOs.AgencyDto#245a26e1, com.project.DTOs.AgencyDto#4d63b624, com.project.DTOs.AgencyDto#466cf502]
Actual :[]
Is this not the right way to test get() methods? Am I doing something wrong when setting the actual result?
if i understand your code coreectly
agencyRepository.findAll() return List<Agency>
agencyService.getAll() return List<AgencyDto>
Issue is here
List<Agency> existingAgencies = new ArrayList<Agency>();
when(agencyRepository.findAll()).thenReturn(existingAgencies);
your mock returns an empty list, you need to add items to list
eg:
List<Agency> existingAgencies = new ArrayList<Agency>();
existingAgencies.add(agencyObjectInDB1);
existingAgencies.add(agencyObjectInDB2);
existingAgencies.add(agencyObjectInDB3);
//Mock repo call
when(agencyRepository.findAll()).thenReturn(existingAgencies);
//I assume Here inside getAll() , agencyRepository.findAll() is invoked
//getAll() converts Agency to AgencyDto
List<AgencyDto> result = agencyService.getAll();
// assert against pre-pepared list
assertEquals(agencies, result);
Related
I am trying to test the following method with JUnit tests, using Mockito:
#Override public List<Adoption> search(String username, Integer id) {
List<Adoption> emptySearchResult = new ArrayList<>();
if(id != null && !username.equals("") ) {
if(!this.petRepository.findById(id).isPresent()){
return emptySearchResult;
}
if(!this.appUserRepository.findByUsername(username).isPresent()){
return emptySearchResult;
}
Pet pet = this.petRepository.findById(id).orElseThrow( () -> new PetNotFoundException(id));
AppUser user = this.appUserRepository.findByUsername(username).orElseThrow( () -> new UsernameNotFoundException(username));
return this.adoptionRepository.findAllByUserAndPet(user, pet);
}
else if(id != null && username.equals("")){
if(!this.petRepository.findById(id).isPresent()){
return emptySearchResult;
}
Pet pet = this.petRepository.findById(id).orElseThrow( () -> new PetNotFoundException(id));
return this.adoptionRepository.findAllByPet(pet);
}
else if(id == null && !username.equals("")) {
if(!this.appUserRepository.findByUsername(username).isPresent()){
return emptySearchResult;
}
AppUser user = this.appUserRepository.findByUsername(username).orElseThrow( () -> new UsernameNotFoundException(username));
return this.adoptionRepository.findAllByUser(user);
}
else {
return this.adoptionRepository.findAll();
}
}
However, I run into a problem with the following part:
if(!this.petRepository.findById(id).isPresent())
Even though I have mocked this.petRepository.findById(id), for some reason isPresent() is returning false. This is my initialization for the tests:
#Mock
private AdoptionRepository adoptionRepository;
#Mock
private PetRepository petRepository;
#Mock
private AppUserRepository appUserRepository;
private AdoptionServiceImpl service;
private Adoption adoption1;
private Adoption adoption2;
private Adoption adoption3;
private AppUser user;
private AppUser user2;
private Pet pet;
private Pet petAlteadyAdopted;
List<Adoption> allAdoptions = new ArrayList<>();
List<Adoption> userFilteredAdoptions = new ArrayList<>();
List<Adoption> petFilteredAdoptions = new ArrayList<>();
#Before
public void init() {
MockitoAnnotations.initMocks(this);
user = new AppUser("username","name","lastname","email#gmail.com","pass",ZonedDateTime.now(), Role.ROLE_USER, City.Skopje);
user2 = new AppUser("username1","name","lastname","email#gmail.com","pass",ZonedDateTime.now(), Role.ROLE_USER, City.Skopje);
Center center = new Center("a", City.Bitola,"url");
pet = new Pet("p", Type.DOG,"b", Gender.FEMALE,"d",center, ZonedDateTime.now(),"url",null,false,ZonedDateTime.now());
petAlteadyAdopted = new Pet("p", Type.DOG,"b", Gender.FEMALE,"d",center, ZonedDateTime.now(),"url",null,true,ZonedDateTime.now());
pet.setId(0);
petAlteadyAdopted.setId(1);
adoption1 = new Adoption(ZonedDateTime.now(),ZonedDateTime.now(),Status.ACTIVE,user,pet);
adoption2 = new Adoption(ZonedDateTime.now(),ZonedDateTime.now(),Status.CLOSED,user,pet);
adoption3 = new Adoption(ZonedDateTime.now(),ZonedDateTime.now(),Status.CLOSED,user2,new Pet());
allAdoptions.add(adoption1);
allAdoptions.add(adoption2);
allAdoptions.add(adoption3);
petFilteredAdoptions.add(adoption2);
petFilteredAdoptions.add(adoption1);
userFilteredAdoptions.add(adoption2);
userFilteredAdoptions.add(adoption1);
Mockito.when(this.adoptionRepository.findById(0)).thenReturn(java.util.Optional.of(adoption1));
Mockito.when(this.adoptionRepository.findById(1)).thenReturn(java.util.Optional.of(adoption2));
Mockito.when(this.petRepository.findById(0)).thenReturn(java.util.Optional.of(pet));
Mockito.when(this.petRepository.findById(1)).thenReturn(java.util.Optional.of(petAlteadyAdopted));
Mockito.when(this.appUserRepository.findByUsername("username")).thenReturn(java.util.Optional.of(user));
Mockito.when(this.appUserRepository.findByUsername("username1")).thenReturn(java.util.Optional.of(user2));
Mockito.when(this.adoptionRepository.findAll()).thenReturn(allAdoptions);
Mockito.when(this.adoptionRepository.findAllByPet(pet)).thenReturn(petFilteredAdoptions);
Mockito.when(this.adoptionRepository.findAllByUser(user)).thenReturn(userFilteredAdoptions);
Mockito.when(this.adoptionRepository.findAllByUserAndPet(user,pet)).thenReturn(userFilteredAdoptions);
Mockito.when(this.adoptionRepository.save(Mockito.any(Adoption.class))).thenReturn(adoption1);
this.service = Mockito.spy(new AdoptionServiceImpl(this.adoptionRepository, this.petRepository,this.appUserRepository));
}
As a result, the following test fails, even though it should pass:
#Test
public void searchTest2() {
List<Adoption> adoptionList = this.service.search("",0);
Assert.assertEquals(petFilteredAdoptions,adoptionList);
}
In order to solve this I tried mocking the isPresent() method:
Mockito.when(this.petRepository.findById(0).isPresent()).thenReturn(true);
But I'm getting the following exception:
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
Boolean cannot be returned by findById() findById() should return
Optional***
If you're unsure why you're getting above error read on. Due to the
nature of the syntax above problem might occur because:
This exception might occur in wrongly written multi-threaded tests. Please refer to Mockito FAQ on limitations of concurrency
testing.
A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
I also tried the following variation:
Mockito.doReturn(true).when(this.petRepository.findById(0)).isPresent();
But then I got the following exception:
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at mk.finki.ukim.milenichinja.ServiceTests.AdoptionServiceFilterTests.init(AdoptionServiceFilterTests.java:87)
E.g. thenReturn() may be missing. Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod(); Hints:
missing thenReturn()
you are trying to stub a final method, which is not supported
you are stubbing the behaviour of another mock inside before 'thenReturn' instruction is completed
Any ideas how to solve this problem?
In the init method, you are stubbing findById on the mock instance this.petRepository to return a non-mock Optional, which is good. In your new test, you are trying to set a return value for isPresent, which you can't do because Optional is not a mock. If you want to override the behavior per-test, you'll need to stub findById to return an Optional of a different instance. Therefore, this is right, though it appears exactly as it does in init and consequently it can't tell you why your test is failing.
Mockito.when(this.petRepository.findById(0))
.thenReturn(java.util.Optional.of(pet));
Mockito works by creating a mock object that subclasses a class and overrides every method. The overridden method is what interacts with a static (ThreadLocal) infrastructure, allowing you to use when syntax. The important thing here is that when ignores its argument, and instead tries to mock the last interaction that you made with a mock. You can find out more in the SO questions How does mockito when() invocation work? and How do Mockito matchers work?.
When you see this call:
Mockito.when(this.petRepository.findById(0))
.thenReturn(java.util.Optional.of(pet));
Then it works as you've intended:
petRepository is a mock, findById is presumably an overridable method, Mockito records the fact that you've called it with the argument 0.
findById doesn't have any behavior stubbed yet, so it does its default, returning null.
when doesn't care that it just received null, because the null doesn't tell it anything about what methods were called to get the null. Instead it looks back at its most recent record (findById(0)) and returns an object with the thenVerb methods you expect.
You call thenReturn, so Mockito sets up petRepository to return the Optional instance you created and passed in.
But when you try this call:
Mockito.when(this.petRepository.findById(0).isPresent()).thenReturn(true);
Then the most recent interaction isn't isPresent, it's findById, so Mockito assumes you want findById(0) to thenReturn(true) and throws WrongTypeOfReturnValue. Optional is not a mock, so interacting with it doesn't let Mockito record its interaction or replay your behavior. For what it's worth, I also wouldn't advise mocking it: Optional is a final class, and though Mockito has recently added some support for mocking final types, Optional is simple and straightforward enough that it makes more sense to just return the Optional instance you want rather than trying to mock it.
With all that said, your code looks right; as long as PetRepository is an interface I don't see anything about the way your method looks or the way your mocks look that would cause this.petRepository.findById(0) to return an absent Optional. In fact, I don't even see where you would create an absent Optional for it to return, so I can only guess that you are using more real objects in your test than you think you are.
I am trying to make a test for the method to delete an entity by id. I've written the test for the case when an entity with the given id doesn't exist, but in case when the entity exists, I'm apparently doing something wrong. This is the delete method from the service. I'm using the deleteById() method of the JpaRepository.
public void deleteById(Integer id) {
Optional<Agency> optionalAgency = repo.findAll().stream()
.filter(agency -> agency.getId().equals(id))
.findFirst();
if (optionalAgency.isPresent()) {
repo.deleteById(optionalAgency.get().getId());
} else {
throw new AgencyNotFoundException("Agency not found");
}
}
And this is my test:
#Mock
private AgencyRepository agencyRepository;
#Mock
private AgencyMapper mapper;
#InjectMocks
private AgencyService agencyService;
#Test
void delete() {
Agency agency = new Agency();
when(agencyRepository.findById(1)).thenReturn(Optional.of(agency));
agencyService.deleteById(1);
verify(agencyRepository).deleteById(1);
}
What assertion should I make in order to verify that the deletion was successful? The way I've tried it it doesn't work, the result of the test is that an exception is thrown. I'm guessing that the exception is thrown because agencyRepository.findById((int) 1L); basically doesn't exist anymore, but I thought maybe there's a better way to verify the deletion, without searching for the deleted object.
Not the answer, but your method could be written something like this:
public void deleteById(Integer id) {
Agency agency = repo.findById(id).orElseThrow(() -> throw new AgencyNotFoundException("Agency not found"));
repo.deleteById(agency.getId());
}
Because:
Optional<Agency> optionalAgency = repo.findAll().stream().filter(agency -> agency.getId().equals(id)).findFirst(); is not efficient. What if you have thousands of agencies? Will you fetch all and filter through all of them just to find by id. You have that method in your repository already.
if (optionalAgency.isPresent()) {} Optional.isPresent is not good practise. Read here and this answer
repo is a mock, so calling deleteById on it won't actually delete anything. Instead, you could verify that calling the AgencyService's deleteById actually calls AgencyRepository's deleteById.
EDIT:
The repository's code uses findAll, not findById, so you need to make sure you mock that:
#Test
void delete() {
Agency agency = new Agency();
agenct.setId((int) 1L);
when(agencyRepository.findAll()).thenReturn(Collections.singletonList(agency));
agencyService.deleteById((int) 1L);
verify(agencyRepository).delteById((int) 1L);
}
I am new in writing the junit test cases and need help. I read about possible solutions but they are not working at this point.
Main class looks like below, which calls the method of ther class addResponseData(This method only sets values in session and returns nothing). Please see the code as per below.
#Test
public void testPublishData_Success() throws java.lang.Exception {
when(GetPropValues.getPropValue(PublisherConstants.ATMID)).thenReturn("ATM");
when(GetPropValues.getPropValue(PublisherConstants.DATA_SOURCE)).thenReturn("PCE");
ReadAndWriteFiles mockFiles = Mockito.mock(ReadAndWriteFiles.class);
PowerMockito.whenNew(ReadAndWriteFiles.class).withNoArguments().thenReturn(mockFiles);
Mockito.when(mockFiles.getAllFiles()).thenReturn(null);
KafkaProducer mockProducer = Mockito.mock(KafkaProducer.class);
PowerMockito.whenNew(ReadAndWriteFiles.class).withAnyArguments().thenReturn(mockProducer);
producer.publishData(null, "Test", "Data1");
}
ResponseWrapper signerResponse;
try {
privateClassObj.ensureDataLoaded(objSession); // Loads the required data into objSession)
signerResponse = new ResponseWrapper(ResponseType.SUCCESS);
signerResponse.addResponseData("signerList", objSession.getSignerList());
signerResponse.addResponseData("additionalSignerList", objSession.getAdditionalSignerList());
}
catch (ServiceException err) {
signerResponse = new ResponseWrapper(ResponseType.PARTIAL_SUCCESS);
}
return signerResponse;
}
TestClass: I have written junit test case as per below.
#Test
public void testSuccessfulCallWithSigners() {
List<Signer> signerList = setSignerList();
List<Signer> additionalSignerList = setSignerList();
when(objSession.getSignerList()).thenReturn(signerList);
when(nsbSession.getAdditionalSignerList()).thenReturn(additionalSignerList);
ResponseWrapper output = signerController.getUsers(request); // actual method call
assertEquals(output, responseWrapper);
}
This test case is failing because, I always get empty signerList and additionalSignerList.(test case result is getAdditionalSignerList() method should return List) Please let me know what am I doing wrong here. Thanks in Advance. I am also posting my the code of setSignerList() in case if you want to see it for reference.
private List<Signer> setSignerList() {
List<Signer> signerList = new ArrayList<Signer>();
signerList.add(primarySigner); // primarySigner is mock object.
return signerList;
}
You have mocked objSession and also you have returned your empty list when these two methods get called by the test case.
when(....).thenReturn(....) is used to specify a condition and a return value (Stubbing) for this condition.As you have mocked it and return your desired list using stubbing, it will not return the list returned by actual call.
List<Signer> signerList = setSignerList(); // EMPTY LIST
List<Signer> additionalSignerList = setSignerList(); // EMPTY LIST
when(objSession.getSignerList()).thenReturn(signerList); //MOCK
when(nsbSession.getAdditionalSignerList()).thenReturn(additionalSignerList); // MOCK
Im helper method use ehcache, to reduce queries to Db. Now want to implement JUnit+Mockito test to ensure that ehcache works properly. Have such variant of test:
#Autowired
private DBService service;
#Autowired
private DiscountHelper discountHelper;
#Autowired
private CacheManager cacheManager;
#Before
public void setUp() throws Exception {
assertNotNull(cacheManager);
}
#Test
public void testGetDiscountWithCache() throws RuntimeException,
InterruptedException {
String id1 = "id1";
String id2 = "id2";
String id3 = "id3";
List<String> discountsId = new ArrayList<String>();
discountsId.add(id1);
discountsId.add(id2);
discountsId.add(id3);
List<Map<String, Object>> attrList = new ArrayList<Map<String, Object>>();
attrList.add(new Discount().getAttributes());
attrList.add(new Discount().getAttributes());
attrList.add(new Discount().getAttributes());
Cache cache = cacheManager.getCache(DiscountHelper.CACHE_NAME);
assertNotNull(cache);
assertEquals(0, cache.getSize());
// First run with empty cache
when(service.getAllItems(eq(Discount.TABLE_NAME))).thenReturn(attrList);
List<Discount> actualResult = discountHelper
.getAllDiscountsUsingCache();
assertNotNull(actualResult);
assertEquals(attrList.size(), actualResult.size());
verify(service).getAllItems(eq(Discount.TABLE_NAME));
cache = cacheManager.getCache(DiscountHelper.CACHE_NAME);
// In cache should be 1 record
assertNotNull(cache);
assertEquals(1, cache.getSize());
}
And test method is:
#Cacheable(cacheName = CACHE_NAME, refreshInterval = 1000 * 900, decoratedCacheType = DecoratedCacheType.REFRESHING_SELF_POPULATING_CACHE)
public List<Discount> getAllDiscountsUsingCache() throws RuntimeException,
InterruptedException {
List<Map<String, Object>> result = dbService
.getAllItems(Discount.TABLE_NAME);
List<Discount> discountList = new ArrayList<Discount>();
for (Map<String, Object> entry : result) {
discountList.add(new Discount(entry));
}
return discountList;
}
And this perfectly works. In test i`m sure that after invocation of method I get something in cache. As you can see I also verify that was called method getAllItems in db service. That is good for first time invocation. Next I add second invocation of discountHelper.getAllDiscountsUsingCache() in the same test like this:
when(service.getAllItems(eq(Discount.TABLE_NAME))).thenReturn(attrList);
actualResult = discountHelper
.getAllDiscountsUsingCache();
assertNotNull(actualResult);
assertEquals(attrList.size(), actualResult.size());
verify(service, times(0)).getAllItems(eq(Discount.TABLE_NAME));
So I just want to check that on second invocation there will not be calls to DB service via method getAllItems by this verify: verify(service, times(0)).getAllItems(eq(Discount.TABLE_NAME)); and result will be obtain from cache.
But it doesn't work, I still get invocation of DB method. I find this tutorial http://blog.goyello.com/2010/07/29/quick-start-with-ehcache-annotations-for-spring/ and try variant with delegate object for ehcache testing, but it still invoke db methods on test. What`s wrong?
By the way in production ehcache works good as I see in logs of tomcat, so this is a problem of test. Any suggestions how to fix it?
In the second invocation you use the same mock object (service) created (as I assume from a question's tag) by Springockito during the Spring context initialization. The mock remembers getAllItems() call from the first invocation. You can:
reset the mock before the second invocation using reset(service),
or
check after the second invocation) if there is still one (not two) getAllItems() invocation.
I'm starting some testing using Mockito on some service classes I use for connecting to my data store. I now want to determine the best practice way writing tests for it. The principle is for each entity there is a way to list, add, delete etc a row from the data store(mongo/mysql etc) for a specific entity.
Take this class that allows me to talk to my database that stores a list of companies
public class CompanyService extends Service{
public CompanyService() {
...
}
public saveCompany(Company company) {
...
}
// get a list of all companies
public List<Company> getCompanies() {
List<Company> companies = new ArrayList<Company>();
try {
CompanyResult<Rows<String, String>> rows = db.query(....);
for (Row<String, String> row : rows.getResult()) {
companies.add(row.getColumns());
}
catch (Exception e){
logger.warn("Error retrieving companies", e);
}
}
}
What exactly should I test in the getCompanies method and how can I use Mockito to do it?
Your System Under Test is the Company Service. You want to test that, assuming all its dependencies/collaborators function properly, it functions properly.
The db object looks like the only dependency/collaborator you need to worry about within the getCompanies() method. Use Mockito to mock the call to db.query()
You could set up a test method like so:
#Test
public void testGetCompanies() {
/*** Arraign ***/
CompanyService cs = new CompanyService();
// Setup mock db
DB mockDb = mock(DB.class);
// Setup fake results for query
CompanyResult<Rows<String, String>> sampleResults = ... // build sample results here
// Have query on mock return fake results
when(db.query(/* match arguments */)).thenReturn(sampleResults);
// Tell your System Under Test to use the mock collaborator
cs.setDB(mockDb);
/*** Act ***/
CompanyResult<Rows<String, String>> results = cs.getCompanies();
/*** Assert ***/
... // Test that results and sampleResults are effectively the same
}
You could test how your code would work if the db query returned and empty result,null or if row has null values or unexpected values. You could mock the db class to return these values. You could also mock the db class to throw an exception to see how your code could react.