I've created a list of columns that I want to retrieve as so:
final Field ciNameField = field("some_column");
...
I put these into a list as so:
ImmutableList<Field> columns = ImmutableList.<Field>builder()
.add(ciNameField)
...
.build();
and finally use these in my query:
Result<Record> fetchMetadata = context.select(columns.asList())
...
.fetch();
This works fine when run as an integration test but has problems when I try to unit test it. Specifically the field(String) is returning null.
Im setting up the test as follows:
#RunWith(PowerMockRunner.class)
#PrepareForTest({DSL.class})
public class ServiceImplTest {
#Mock
PostgresDatasource pgClient;
#InjectMocks
ServiceImpl service = new ServiceImpl();
#Test
public void checkParamsUsedTest() {
DSLContext context = mock(DSLContext.class);
PowerMockito.mockStatic(DSL.class);
...
and so on.
Other than this snag the mocking / testing works fine.
Im guessing there's either some setup for jooq / fields that I've missed or some testing caveat where this type of operation isn't supported.
Edit:
Other jooq methods that don't seem to work when run via PowerMockito:
name
(un)quotedName
These return null.
Related
I can't find a way to test my update method using JUnit. I am mocking the necessary repo and services. But when I call findById(Mockito.any()) it can't find anything so it throws an exception.
Here is my test class:
#ExtendWith(MockitoExtension.class)
class ApplicantServiceTest {
#Mock
private ApplicantRepository applicantRepository;
#Mock
private CreditRatingService creditRatingService;
#Mock
private ApplicantMapper applicantMapper;
#InjectMocks
private ApplicantService applicantService;
#Test
void update() {
Applicant applicant = getSampleApplicants().get(1);
Applicant updatedApplicant = new Applicant(1L,2141245L,"ege","c0skun",2523,"21412412",null,null);
Mockito.when(applicantService.update(applicantMapper.toDTO(applicant),Mockito.any())).thenReturn(applicant);
Assert.assertEquals(applicant.getIdentificationNumber(),updatedApplicant.getIdentificationNumber());
Assert.assertEquals(applicant.getPhoneNumber(), updatedApplicant.getPhoneNumber());
Assert.assertEquals(applicant.getFirstName(), updatedApplicant.getFirstName());
assertEquals(applicant.getMonthlyIncome(), updatedApplicant.getMonthlyIncome());
Assert.assertEquals(applicant.getId(), updatedApplicant.getId());
}
And this is the method I am trying to test:
public Applicant update(ApplicantDTO applicantDTO,Long id) {
Applicant byId = getById(id);
if (applicantDTO.getMonthlyIncome()!=byId.getMonthlyIncome()){
byId.setMonthlyIncome(applicantDTO.getMonthlyIncome());
}
if (!Objects.equals(applicantDTO.getFirstName(), byId.getFirstName())){
byId.setFirstName(applicantDTO.getFirstName());
}
if (!Objects.equals(applicantDTO.getLastName(), byId.getLastName())){
byId.setLastName(applicantDTO.getLastName());
}
if (!Objects.equals(applicantDTO.getPhoneNumber(), byId.getPhoneNumber())){
byId.setPhoneNumber(applicantDTO.getPhoneNumber());
}
if (!Objects.equals(applicantDTO.getIdentificationNumber(), byId.getIdentificationNumber())){
byId.setIdentificationNumber(applicantDTO.getIdentificationNumber());
}
return applicantRepository.save(byId);
}
This is the output:
17:43:19.520 [main] ERROR com.egecoskun.finalproject.services.ApplicantService - Applicant not found by id : null
Related Applicant not found with : [id : null]
EntityNotFoundException(details=Some Special Details)
at com.egecoskun.finalproject.services.ApplicantService.lambda$getById$0(ApplicantService.java:47)
at java.base/java.util.Optional.orElseThrow(Optional.java:403)
at com.egecoskun.finalproject.services.ApplicantService.getById(ApplicantService.java:45)
at com.egecoskun.finalproject.services.ApplicantService.update(ApplicantService.java:75)
at com.egecoskun.finalproject.services.ApplicantServiceTest.update(ApplicantServiceTest.java:136)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...
Can someone explain how to unit test my update method?
The problem with your test code is that you've mixed mocking a method for a mock object (e.g. applicantRepository) with calling the tested method on an object under test (applicantService). We use when(...) to define the mocked behavior in Mockito and after that the actually tested code should be called (without the when()).
What you probably want to do is: mock retrieving the applicant object by ID, mock saving the modified object, run the update method to test it and assert the result.
To mock the behavior of the applicantRepository you need to tell Mockito what is the expected outcome of its methods calls, for example (I made a few assumptions for the code that is not attached):
when(applicantRepository.findById(anyLong())).thenReturn(applicantFromDb);
when(applicantRepository.save(notNull())).thenAnswer(returnsFirstArg());
(applicantFromDb is an object created in the test method)
After that when you call your update method, the mocked behavior above will be used:
Applicant result = applicantService.update(...);
Now you can assert the result returned from the tested method.
ApplicationService is your class under test. The exception you're getting is coming from ApplicationService.getById() method called at the start of update() method you're testing. You did not show us that method, but at a guess it calls the repository to get an instance by id. Your Repository mock is not set up to return anything when asked for any entity, so it returns null. Which seems to trigger the orElseThrow clause in the getById() method.
As such what you're seeing is likely the expected behaviour - when trying to update with an id that does not exist in the repository (repository returns null) service throws an exception. If you want to test the case where the entity is present you need to mock the repository appropriately.
I have a test class that is annotated with #Spy and #InjectMocks and tested using Mockito. The class under test has a value (url) that is retrieved from the application.properties file. I'd like to test whether this url is being set correctly within the method that uses it. I can do this if I remove the #Spy and #InjectMocks annotations and use #Autowire and #SpringBootTest. However, that breaks other tests that use the spy functionality, so I'm just wondering if there's any way we can keep the spy working and test all our methods inside the same file, maybe without the need to bring in the #SpringBootTest annotation and the autowiring? The workaround we're using for now is to have two files, one that uses the spy and the other that tests the specific method to do with the properties file and that requires the full context to load, but not sure that's the best solution here?
Here is the test with the spy:
#ExtendWith(MockitoExtension.class)
class ProviderHelperServiceTest {
#Spy
#InjectMocks
ProviderHelperService providerHelperService;
#Value("${viaduct-url}")
String viaductUrl;
#Test
void testGetRequestBodyUriSpec() {
WebClient.RequestBodyUriSpec requestBodyUriSpec = providerHelperService.getRequestBodyUriSpec("sifToken");
final String[] url = new String[1];
requestBodyUriSpec.attributes(httpHeaders -> {
url[0] = (String) httpHeaders.get("org.springframework.web.reactive.function.client.WebClient.uriTemplate");
});
// Fails as url[0] comes back as null. Disabled and moved to another file.
assertEquals(viaductUrl, url[0]);
}
#SpringBootTest
class ProviderHelperService2Test {
#Autowired
ProviderHelperService providerHelperService;
#Value("${viaduct-url}")
String viaductUrl;
#Test
void testGetRequestBodyUriSpec() {
WebClient.RequestBodyUriSpec requestBodyUriSpec = providerHelperService.getRequestBodyUriSpec("sifToken");
final String[] url = new String[1];
requestBodyUriSpec.attributes(httpHeaders -> {
url[0] = (String) httpHeaders.get("org.springframework.web.reactive.function.client.WebClient.uriTemplate");
});
assertEquals(viaductUrl, url[0]);
}
}
And here is the method under test:
public class ProviderHelperService {
#Value("${viaduct-url}")
String viaductUrl;
public WebClient.RequestBodyUriSpec getRequestBodyUriSpec(String sifToken) {
WebClient.RequestBodyUriSpec requestBodyUriSpec = WebClient.create().post();
requestBodyUriSpec.header("Authorization", sifToken);
requestBodyUriSpec.uri(viaductUrl);
return requestBodyUriSpec;
}
}
The cleanest way to perform such tests is to replace field injection with constructor injection, and then you can quite easily confirm that the value that's passed into the class comes back out the service call.
If you're using Boot, it's usually best to replace use of #Value with #ConfigurationProperties. Depending on the specifics, you can either pass the whole properties object to the service's constructor or write an #Bean configuration method that unpacks the relevant properties and passes them as plain constructor parameters with new.
As the title states, I can call verifyPrivate but it always gives me success even if I pass the wrong parameters to it.
Real example
#RunWith(PowerMockRunner.class)
#PrepareForTest({MyService.class})
public class MyServiceTest {
#InjectMocks
MyService service;
#Mock
OperationSivRepo operationSivRepo;
#Test
public void getNbInscriptions_should_call_getNbOperationsSiv_with_OPERATION_INSCRIPTION_GAGE() throws Exception {
// GIVEN
Role role = Role.ADMINISTRATEUR;
String operator = "operator";
SivDto sivDto = new SivDto();
// WHEN
service.getNbInscriptions(operator, role, sivDto);
// THEN
verifyPrivate(service).invoke("privateMethod", operator, Role.ADMINISTRATEUR, sivDto);
}
}
Now this code will succeed, even if I do something like
// THEN
verifyPrivate(service).invoke("privateMethod", "other string", Role.USER, new SivDto());
Maybe I'm missing something but I just can't figure it out.
Firstly. Did you put a debug point in privateMethod and see how many times it is getting called? This would have given you some hint.
It is getting called two times. Once when you call
service.getNbInscriptions(operator, role, sivDto);
and once when you use
verifyPrivate(service).invoke("privateMethod", operator, Role.ADMINISTRATEUR, sivDto);
Second time since it is getting called with the arguments you passed to invoke method, the tests always succeed.
Use Spy instead of Mock
Instead of
#InjectMocks
MyService service;
Use
#Spy
MyService myservice = new MyService(operationSivRepo)
Wiht this, second invocation to the method is not made and arguments are verified properly.
I'm woking on EJB Project, using JPA to query data. Now, I create unit test and use mockito to mock data. There is a function that I call data from criteria builder, and it's called from #PostConstruct. So if result is empty, then it will throw NoResultException. However, I am unable to run unit test to test it. Take a look on source code below:
For class RefdataUpdateDaoImpl
public class RefdataUpdateDaoImpl{
public RefdataUpdate getSingleUpdate() {
CriteriaBuilder cb = getCriteriaBuilder();
CriteriaQuery<RefdataUpdate> query = cb.createQuery(RefdataUpdate.class);
Root<RefdataUpdate> rootEntry = query.from(RefdataUpdate.class);
CriteriaQuery<RefdataUpdate> all = query.select(rootEntry);
TypedQuery<RefdataUpdate> allQuery = getEntityManager().createQuery(all);
return allQuery.getSingleResult();
}
}
In RefDataCacheBean
#PostConstruct
private void postConstruct() throws Exception{
cachedUpdateTs = RefdataUpdateDaoImpl.getLastUpdate();
}
This is unit test
#Test(expected = NoResultException.class)
public void testExistingRefDataUpdate() throws NoResultException{
update.deleteRefDataUpdate();
refdataServiceBean.getLastUpdate();
}
So in unit test, it loads data from dataset xml. So when I run test, it supposes to throw NoResultException and test passes, but test fails and console log no entity data found.
Please help to create unit test in this case, when function's called from #PostConstruct.
Trace Logs:
javax.ejb.EJBException: javax.persistence.NoResultException: No entity found for query
Thank you and any comments will be appreciated.
Obviously the NoResultException is nested in a EJBException so your test code should be:
#Test(expected = EJBException.class)
public void testExistingRefDataUpdate() throws NoResultException{
update.deleteRefDataUpdate();
refdataServiceBean.getLastUpdate();
}
I have a problem with getting result from method which is not mocked. I dont want to mock the result but to achieve the real result from this method. The method works in application, so this is not the problem. I have a test:
#Test
public void shouldGetCompaniesToSelect() throws Exception {
Company company = new Company("company", new Address());
Company relatedCompany1 = new Company("relatedCompanyName1", new Address());
Company notRelatedCompany = new Company("notRelatedCompanyName", new Address());
Company relatedCompany2 = new Company("relatedCompanyName2", new Address());
CompanyRelation companyRelation1 = new CompanyRelation(relatedCompany1);
CompanyRelation companyRelation2 = new CompanyRelation(relatedCompany2);
company.getCompanyRelations().add(companyRelation1);
company.getCompanyRelations().add(companyRelation2);
when(companyServiceMock.findAll()).thenReturn(Arrays.asList
(company, relatedCompany1, notRelatedCompany, relatedCompany2));
when(companyServiceMock.findOne(1L)).thenReturn(company);
List<Company> companiesToSelect = companyServiceMock.findCompaniesToSelect(company);
mockMvc.perform(get("/company/1"))
.andExpect(model().attribute("companiesToSelect", hasSize(1)))
.andExpect(model().attribute("companiesToSelect", hasItem(
hasProperty("relatedCompany", hasProperty(
"name", is("notRelatedCompanyName")
)))));
}
There are 2 mocked methods (findAll and findOne) and then I want to execute method and get real results from findCompaniesToSelect(company - this is object created to test). Size of the companiesToSelect should be 1, but it returns 0.
findCompaniesToSelect method:
public List<Company> findCompaniesToSelect(Company company) {
List<Company> companiesToSelect = companyRepository.findAll();
for (CompanyRelation companyRelation :
company.getCompanyRelations()) {
companiesToSelect.remove(companyRelation.getRelatedCompany());
}
companiesToSelect.remove(company);
return companiesToSelect;
}
How can I do that?
EDIT 1:
Okay, so I've changed it into #Spy and changed stubs into:
Mockito.doReturn(Arrays.asList(company, relatedCompany1,
notRelatedCompany, relatedCompany2)).when(companyServiceMock).findAll();
Mockito.doReturn(company).when(companyServiceMock).findOne(1L);
But when I run the test, the findCompaniesToSelect() method is using real companies instead of mocked companies.
Okay, so now the problem is when the findCompaniesToSelect() method is called, the companyRepository.findAll method is called. I want to call mocked findAll method from test to get mocked companies instead of real companies.
EDIT 2:
Okay, the problem was because findCompaniesToSelect() method uses repository, not a service. :D
If you want to have a combination of mocked methods and real method calls on an object then you need to use a spy instead of a mock.
#Spy
CompanyService companyServiceSpy
You will need to stub your mock methods differently though. using doReturn(...).when(...) instead of the stubbing you are currently using.
Have a look at http://www.baeldung.com/mockito-spy for more information on using spies.
EDIT: Since you are mocking some behaviour in your test you should use a standalone set up for your MockMvc object and inject the mock into your controller like so:
MockMvc mockMvc;
#Spy
CompanyService companyServiceSpy;
#InjectMocks
CompanyController companyController;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(companyController).build();
}
EDIT 2: You may also be able to resolve this just by changing #Spy to #SpyBean in your current set up. Not 100% sure on this because i'm not fully familiar with how Spring boot sets up tests.
This is happening because your service class i.e. companyService is mocked.
I should suggested to use Restassured for testing your Restservice, where it didn't require to create mock for different methods of your RestService components i.e. you don't need to mock CompanyService.
For further reading:
RestAssured
Example Code for RestAssured testing