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();
}
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'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.
I'm a bit confused.
How can I get TestNG to report an error for a test?
// ...
#DataProvider(name = "foo")
public Object[][] provideData () {
throw new SomeRuntimeException("Some error occurred. The test configuration "
+ "is somehow incorrect.");
}
This will just lead to test skipping. The exception doesn't even get logged.
Moving this to a constructor will just get the exception logged but that's not enough...
I want a big fat error message.
At the moment, using a dedicated (self) test method does the job which at leasts shows some test failure...
Anyway, it would be nice to know how testNG's definition of an error looks like.
Thank you for any hints!
Here is the article which proposes fair set of alternatives with detailed enough explanations:
Fail instead of Skip a Test when TestNG’s DataProvider throws an Exception
For me best way happened to add test for data providers and here is brief illustration of idea:
public class MyClass {
#DataProvider(name = "my-data-provider")
private Object [][] myProvider() {
// ...
}
#Test
public void testDataProviders() {
Assert.assertTrue(myProvider().length > 0);
}
#Test
// ... Real tests.
}
I am investigating the use of Spring Data Rest (2.0.1.RELEASE and Spring 4.0.2.RELEASE), and have written a simple service. I have also written a simple test class (see below) using DbUnit.
Unfortunately when I run the tests only the findAll method passes. If I comment out the findAll method then the findInvestigationalProductById passes and directLink fails. If I then comment out findInvestigationalProductById then directLink passes.
None of these methods changes data state, so I would like to know if there is some configuration I have overlooked that can cause this behaviour.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/com/perceptive/ctms/core/tests-context.xml"})
#WebAppConfiguration
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DbUnitTestExecutionListener.class })
#DatabaseSetup("investigational-products-data.xml")
public class InvestigationalProductTests {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext wac;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
MockitoAnnotations.initMocks(this);
}
#Test
public void findAll() throws Exception {
ResultActions resultActions = mockMvc.perform(get("/investProduct"))
.andExpect(status().isOk())
.andExpect(content().contentType("application/hal+json"));
resultActions.andExpect(jsonPath("$_embedded.investigationalProduct", hasSize(3)));
resultActions.andExpect(jsonPath("$_embedded.investigationalProduct[0].investigationalProductCode", is("ACTIVE1")));
resultActions.andExpect(jsonPath("$_embedded.investigationalProduct[1].investigationalProductCode", is("ACTIVE2")));
resultActions.andExpect(jsonPath("$_embedded.investigationalProduct[2].investigationalProductCode", is("ACTIVE3")));
}
#Test
public void directLink() throws Exception {
ResultActions resultActions = mockMvc.perform(get("/investProduct/3"))
.andExpect(status().isOk())
.andExpect(content().contentType("application/hal+json"));
System.out.println(resultActions);
resultActions.andExpect(jsonPath("$investigationalProductCode", is("ACTIVE3")));
}
#Test
public void findInvestigationalProductById() throws Exception {
ResultActions resultActions = mockMvc.perform(get("/investProduct/search/findInvestigationalProductById?id=3"))
.andExpect(status().isOk())
.andExpect(content().contentType("application/hal+json"));
resultActions.andExpect(jsonPath("$_embedded.investigationalProduct", hasSize(1)));
resultActions.andExpect(jsonPath("$_embedded.investigationalProduct[0].developmentName", is("developmentName3")));
}
}
This is a misunderstanding about how #DatabaseSetup works. The problem tests are all dealing with referencing data by a generated id. The API states:
Test annotation which indicates how to put a database into a know
state before tests are run. This annotation can be placed on a class
or on methods. When placed on a class the setup is applied before each
test methods is executed.
which to my mind is a little ambiguous, but additional documentation states:
By default setup will perform a CLEAN_INSERT operation, this means
that all data from tables referenced in the DataSet XML will be
removed before inserting new rows.
i.e. tests should not assume that the database (including any sequence numbers) is put into a clean state, just that the data is clean.
Adding the following code
private static int currentOffset = 0;
private static final int TEST_OFFSET = 3;
/**
* After each test is run DatabaseSetup annotation deletes records
* and inserts fresh ones - this means we need to keep track of the
* current offset
*/
#After
public void offset() {
currentOffset += TEST_OFFSET;
}
(with occasional modifications to currentOffset when testing inserts) can keep track of the current ids.
This does not seems ideal, but I do not know a way of resetting the database to a truly clean state.
I am making Test of My classes so I am inserting so many data for to test my code.
So I am thinking to make some mechanism of savepoint and rollback in DB.
I am using postgresql as DB sever.
Following is my code for test :
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration("file:src/main/webapp/WEB-INF/ls-dispatcher-servlet.xml")
public class AddBindingProcessorTest extends IntegrationTestBase {
#Autowired
private AddBindingProcessor processor;
public AddBindingProcessorTest(){
}
#Before
public void setUp() throws Exception {
}
#After
public void tearDown() throws Exception {
}
#Test
public void add() throws Exception {
AddBinding command;
command = new AddBinding();
command.setId(50l);
command.setBindingName("bindingtest1");
command.setBindingPrice((double)253);
BindingTypeResponse response = (BindingTypeResponse)processRequest(command);
System.out.println("from addbindingprocessor test "+response.getBindingName());
}
}
Here I am setting value through command object and passing to ProcessRequest() Method that will store data inside DB using hibernate.
Still I have to write assert in my testProcess() method that will check data is correct or not ?
So my question is that I when this transaction starts in setUp() method one savepoint should be created and then testProcess() method will be executed and assert check for the data that they are correct or not and then in tearDown() method I want to rollback to savepoint that is set in setUp() method.
So how to do so ? If Anyone can just guide me that what I ll have use and how to move forward then I ll learn that thing and go by myself.
I just want guidance about it that what I ll have to use and where ?
Thank You All.
If I get you right, you can just use the
#TransactionConfiguration(defaultRollback = true)
annotation below your #ContextConfiguration annotation.
This will rollback the changes in your tests after every run.
user3145373 pointed out, that the attribute transactionManager="context bean transaction manager" in #TransactionConfiguration needed to be set also.
It is part of the spring-test lib.