I have this method to update a table in DB, it works correctly, until I create the unit test for it:
public class ReferentialAdapter {
private final JPAQueryFactory queryFactory;
public void enableServiceConfigs(String roleCode, String countryIsoCode, List<String> services) {
QServiceConfigEntity qServiceConfigEntity = QServiceConfigEntity.serviceConfigEntity;
QCountryRoleEntity qCountryRoleEntity = QCountryRoleEntity.countryRoleEntity;
QServiceEntity qServiceEntity = QServiceEntity.serviceEntity;
JPQLQuery<Long> countryRoleId = JPAExpressions.select(qCountryRoleEntity.id).from(qCountryRoleEntity)
.where(qCountryRoleEntity.country.isoCode.equalsIgnoreCase(countryIsoCode).and(qCountryRoleEntity.role.code.equalsIgnoreCase(roleCode)));
BooleanExpression whereCondition = qServiceConfigEntity.countryRole.id.eq(countryRoleId)
.and(qServiceConfigEntity.service.id.in(serviceIds));
queryFactory.update(qServiceConfigEntity)
.where(whereCondition)
.set(qServiceConfigEntity.isEnabled, Boolean.TRUE)
.execute();
}
}
configuration for JPAQueryFactory:
#Configuration
public class QueryDslConfig {
#PersistenceContext
private EntityManager entityManager;
#Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(entityManager);
}
}
but this test throw a null pointer exception when call the execute() for the update.
#ExtendWith(MockitoExtension.class)
class ReferentialAdapterTest {
#Mock
private JPAQueryFactory queryFactory;
#InjectMocks
private ReferentialAdapter referentialAdapter;
#Test
void shouldEnableServicesConfig() {
String roleCode = "CA_ICS_HBE";
String countryIsoCode= "FR";
List<String> services = Arrays.asList("VT" , "CAF");
referentialAdapter.enableServiceConfigs(roleCode,countryIsoCode,services);
verify(queryFactory,times(1)).update(any());
}
}
Related
I try write service test, for example, I have this ExamServiceImpl:
#Service
public class ExamServiceImpl implements ExamService {
#Autowired
private final SubjectService scoreService;
private final ScoreDAO scoreDAO;
#Autowired
public ExamServiceImpl(ScoreDAO scoreDAO) {
this.scoreDAO = scoreDAO;
}
#Override
public ResponseModel insertScore(RequestModel request) throws IOException {
SubjectModel subject = scoreService.getNameSubject(request);
ScoreModel score = new ScoreModel();
score.setStudentName(request.getStudentName);
score.setScore(request.getStudentScore);
score.setSubject(subject.getName);
int result = scoreDAO.insert(score);
return result;
}
}
Sample my test:
#SpringBootTest
public class ExamServiceImplTest {
#MockBean
private ScoreDAO scoreDAO;
#Autowired
private SubjectService subjectService;
#Autowired
private ExamService examService;
#Test
void insertScoreTest() {
SubjectModel resFromSubject = new SubjectModel();
resFromSubject.setSubject("Math");
Mockito.when(subjectService.getNameSubject(new RequestModel())).thenReturn(resFromSubject);
Mockito.when(scoreDAO.insert(new ScoreModel())).thenReturn(1);
int resultTest = examService.insertScore(new RequestModel());
assertSame(ex, 1);
}
But output resultTest is 0. I try debugger, I found mock scoreDAO.insert() return 0 >> is not working.
And I try like this:
#SpringBootTest
#RunWith(MockitoJUnitRunner.class)
public class ExamServiceImplTest {
#Mock
private ScoreDAO scoreDAO;
#Mock
private SubjectService subjectService;
#InjectMocks
private ExamService examService = ExamServiceImpl(scoreDAO);
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
void insertScoreTest() {
SubjectModel resFromSubject = new SubjectModel();
resFromSubject.setSubject("Math");
Mockito.when(subjectService.getNameSubject(new RequestModel())).thenReturn(resFromSubject);
Mockito.when(scoreDAO.insert(new ScoreModel())).thenReturn(1);
int resultTest = examService.insertScore(new RequestModel());
assertSame(ex, 1);
}
It's not work too.
Please, could you help write me test methods? I covered with tests more simple other services.
Thank you!
It doesn't work because new ScoreModel() inside Mockito.when() and inside ExamServiceImpl are two different objects. If you want scoreDAO to return 1 for every ScoreModel passed to it you can use:
Mockito.when(scoreDAO.insert(Mockito.any(ScoreModel.class)).thenReturn(1);
I'm having trouble figuring out why Mockito is throwing a NullPointerException when I'm telling the mock to return true.
Here is my JUnit Test:
public class PizzaValidatorTest {
private Pizza meatPizza;
private PizzaValidator validator = new PizzaValidator();
#MockBean
private IngredientRepository ingredientRepository;
#MockBean
private PizzaSizeRepository pizzaSizeRepository;
#Before
public void setUp() throws Exception {
meatPizza = new Pizza();
validator = new PizzaValidator();
}
#Test
public void validateValid() {
when(ingredientRepository.existsById(any())).thenReturn(true);
when(pizzaSizeRepository.existsById(any())).thenReturn(true);
assertTrue(validator.validate(meatPizza));
}
}
The PizzaValidator class is implemented below:
#Controller
public class PizzaValidator implements Validator<Pizza> {
#Autowired
IngredientRepository ingredientRepository;
#Autowired
PizzaSizeRepository pizzaSizeRepository;
#Override
public boolean validate(Pizza entity) {
return validatePizza(entity);
}
private boolean validatePizza(Pizza pizza) {
return validPizzaSize(pizza) && validIngredients(pizza);
}
private boolean validPizzaSize(Pizza pizza) {
return pizzaSizeRepository.existsById(pizza.getSizeDesc().getId());
}
private boolean validIngredients(Pizza pizza) {
for (Ingredient ingredient : pizza.getIngredients()) {
if (!ingredientRepository.existsById(ingredient.getId())) {
return false;
}
}
return true;
}
}
For some reason it seems like Mockito isn't connecting the mock repository with my class repository, but I can't figure out why. Any help is appreciated. Thanks.
You should not create the PizzaValidator using new keyword, you should #Autowire it in the test
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class PizzaValidatorTest {
private Pizza meatPizza;
#Autowire
private PizzaValidator validator;
#MockBean
private IngredientRepository ingredientRepository;
#MockBean
private PizzaSizeRepository pizzaSizeRepository;
#Before
public void setUp() throws Exception {
meatPizza = new Pizza();
}
#Test
public void validateValid() {
when(ingredientRepository.existsById(any())).thenReturn(true);
when(pizzaSizeRepository.existsById(any())).thenReturn(true);
assertTrue(validator.validate(meatPizza));
}
}
I am trying to mock the behavior of a method that is called inside another so that it simulates the return of an object and another time it raises an exception but not if exactly if it is possible and if it is how it would be possible.
#Service
#Transactional
public class CategoryService {
#Autowired
private CategoryRepository repository;
public Category findById(Integer id) {
Optional<Category> obj = repository.findById(id);
return obj.orElseThrow(() -> new ObjectNotFoundException(id.toString()));
}
public Category update(Category category){
// Throws ObjectNotFoundException if not found before update
this.findById(category.getId());
return repository.save(category);
}
}
#RunWith(MockitoJUnitRunner.class)
public class CategoryServiceUnitTest {
#Mock
private CategoryService service;
#Test()
public void Should_UpdateCategory_When_FindCategory() {
Category cat = new Category(1, "Test");
//Is it possible?
when(service.findById(Mockito.anyInt())).thenReturn(cat);
Category category = service.update(cat);
assertThat(category.getName()).isEqualTo(cat.getName());
verify(service, times(1)).update(cat);
}
#Test(expected = ObjectNotFoundException.class)
public void Should_ThrowsObjectNotFoundException_When_NotFoudCategoryById() {
Category cat = new Category(1, "Test");
//Is it possible?
when(service.findById(Mockito.anyInt())).thenThrow(ObjectNotFoundException.class);
service.update(cat);
}
}
As pointed out in the comments, what you want to do is mock CategoryRepository in your test.
#RunWith(MockitoJUnitRunner.class)
public class CategoryServiceTest {
private CategoryService service;
#Mock
private CategoryRepository repository;
#Before
public void setup() {
service = spy(new CategoryService(repository));
}
#Test
public void Should_UpdateCategory_When_FindCategory() throws ObjectNotFoundException {
Category cat = new Category(1, "Test");
when(repository.findById(Mockito.anyLong())).thenReturn(Optional.of(cat));
//return the category object that is used to call the repository.save(...) method
when(repository.save(Mockito.any(Category.class)))
.thenAnswer((Answer<Category>) invocation -> {
Object[] args = invocation.getArguments();
return (Category) args[0];
}
);
//depending on your requirements the above might be overkill, just replace that logic with this
//when(repository.save(Mockito.any(Category.class))).thenReturn(cat);
Category category = service.update(cat);
assertThat(category).isNotNull();
assertThat(category.getName()).isEqualTo(cat.getName());
verify(service).update(cat);
}
#Test(expected = ObjectNotFoundException.class)
public void Should_ThrowsObjectNotFoundException_When_NotFoudCategoryById() throws ObjectNotFoundException {
Category cat = new Category(1, "Test");
when(service.findById(Mockito.anyLong())).thenThrow(ObjectNotFoundException.class);
service.update(cat);
}
}
You'll also need to handle the checked exception ObjectNotFoundException. I just added the exception to the method signature, you might want to handle it differently in a production setting
#Service
#Transactional
public class CategoryService {
private final CategoryRepository repository;
#Autowired
public CategoryService(CategoryRepository repository) {
this.repository = repository;
}
public Category findById(Long id) throws ObjectNotFoundException {
Optional<Category> obj = repository.findById(id);
return obj.orElseThrow(() -> new ObjectNotFoundException(id.toString()));
}
public Category update(Category category) throws ObjectNotFoundException {
// Throws ObjectNotFoundException if not found before update
this.findById(category.getId());
return repository.save(category);
}
}
I have a junit test method as follows:
#SpringBootTest
public class StoreIdAssignmentServiceTest {
private static final Logger log = LoggerFactory
.getLogger(StoreIdAssignmentServiceTest.class);
#InjectMocks
private StoreIdAssignmentService storeIdAssignmentService;
#Mock
private StoreIdAssignmentFactory storeIdAssignmentFactory;
#Mock
private DatabaseService databaseService;
#Test
public void rollUpFeed_Single_DealerAndStoreID_NoExisting() {
List<ScmsaPosTransRollup> scmsaPosTransRollupFeedList = new ArrayList<>();
ScmsaPosTransRollup posTransRollup = new ScmsaPosTransRollup();
posTransRollup.setJobLogId(8269726L);
posTransRollup.setDealerCode("3119255");
posTransRollup.setStoreId("9842");
posTransRollup.setTransactionDate(Timestamp
.valueOf("2018-03-01 13:00:00.00"));
posTransRollup.setQuantity(4);
posTransRollup.setRollupType("H");
scmsaPosTransRollupFeedList.add(posTransRollup);
Mockito.when(
databaseService.getUnProcessedRollUpFeedBasedonRollupType("H"))
.thenReturn(scmsaPosTransRollupFeedList);
List<PosHourlySt> existingPosHourlyStEntries = new ArrayList<>();
Mockito.when(databaseService.getDealerCodeFromPosHourly("3119255"))
.thenReturn(existingPosHourlyStEntries);
Mockito.when(databaseService.getDealerCodeFromPosHourly("3119255"))
.thenReturn(existingPosHourlyStEntries);
storeIdAssignmentService.processHourlyStateFeed();
assertNotNull(posHourlyStRepository.findAll());
}
}
And My StoreIdAssignmentService class will be:
#Service
public class StoreIdAssignmentService {
private StoreIdAssignmentFactory storeIdAssignmentFactory;
private DatabaseService databaseService;
#Autowired
public StoreIdAssignmentService(StoreIdAssignmentFactory storeIdAssignmentFactory,
DatabaseService databaseService) {
this.storeIdAssignmentFactory = storeIdAssignmentFactory;
this.databaseService = databaseService;
}
public void processHourlyStateFeed() {
.......................
calculateStateForPosHourlyStTransaction(posHourlyStToConsider, newPosHourlyStEntries);
.........
}
List<ScmsaPosTransRollup> scmsaPosTransRollupUpdatedFlagList = storeIdAssignmentFactory
.createUpdatedRollUpEntries(rollUpFeedByDealerCode);
saveAndUpdatePosHourlyStAndRollUpEntries(newPosHourlyStEntries, existingPosHourlyStEntries,
rollUpFeedByDealerCode, scmsaPosTransRollupUpdatedFlagList);
}
}
private Map<String, List<ScmsaPosTransRollup>> groupDealerCodeRollUpFeedByStoreId(
List<ScmsaPosTransRollup> rollUpFeedByDealerCode) {
// Grouping the rollUpFeedByDealerCode by storeID
return rollUpFeedByDealerCode.stream().collect(Collectors.groupingBy(ScmsaPosTransRollup::getStoreId));
}
private void calculateStateForPosHourlyStTransaction(ScmsaPosTransRollup scmsaPosTransRollupToConsider, List<PosHourlySt> newPosHourlyStEntries) {
List<PosHourlySt> posHourlyStList = newPosHourlyStEntries.stream().filter(
hourlyState -> (hourlyState.getStartDate().before(scmsaPosTransRollupToConsider.getTransactionDate())))
.collect(Collectors.toList());
..............
PosHourlySt posHourlySt=storeIdAssignmentFactory.createHourlyStEntryFromRollUp(scmsaPosTransRollupToConsider,
Timestamp.valueOf(scmsaPosTransRollupToConsider.getTransactionDate().toLocalDateTime().withHour(0).withMinute(0)),
Timestamp.valueOf(scmsaPosTransRollupToConsider.getTransactionDate().toLocalDateTime().withHour(23).withMinute(59)));
newPosHourlyStEntries.add(posHourlySt);
....................
}
}
and My Factory class would be:
#Component
public class StoreIdAssignmentFactory {
private static final Logger log = LoggerFactory.getLogger(StoreIdAssignmentFactory.class);
private ModelMapper modelMapper;
#Autowired
public StoreIdAssignmentFactory(ModelMapper modelMapper) {
this.modelMapper = modelMapper;
}
public PosHourlySt createHourlyStEntryFromRollUp(ScmsaPosTransRollup scmsaPosTransRollup, Timestamp startDate, Timestamp endDate){
PosHourlySt posHourlySt = new PosHourlySt();
posHourlySt.setDealerCode(scmsaPosTransRollup.getDealerCode());
posHourlySt.setSourceJobLogId(scmsaPosTransRollup.getJobLogId());
posHourlySt.setStartDate(startDate);
posHourlySt.setStoreId(scmsaPosTransRollup.getStoreId());
posHourlySt.setEndDate(endDate);
posHourlySt.setJobLogId(0L);
posHourlySt.setSource("ROLLUP");
log.info("New Rec: {}", posHourlySt.toString());
return posHourlySt;
}
public PosHourlySt createHourlyStEntryFromPosHourlySt(PosHourlySt posHourlyStToSplit, Timestamp endDate){
PosHourlySt posHourlySt = new PosHourlySt();
posHourlySt.setDealerCode(posHourlyStToSplit.getDealerCode());
posHourlySt.setSourceJobLogId(posHourlyStToSplit.getJobLogId());
posHourlySt.setStartDate(posHourlyStToSplit.getStartDate());
posHourlySt.setStoreId(posHourlyStToSplit.getStoreId());
posHourlySt.setEndDate(endDate);
posHourlySt.setJobLogId(0L);
posHourlySt.setSource("ROLLUP");
log.info("SplitupRec: {}", posHourlySt.toString());
return posHourlySt;
}
public List<ScmsaPosTransRollup> createUpdatedRollUpEntries(List<ScmsaPosTransRollup> rollUpFeedByDealerCode) {
List<ScmsaPosTransRollup> scmsaPosTransRollupUpdatedFlagList = new ArrayList<>();
for(ScmsaPosTransRollup scmsaPosTransRollupFeed : rollUpFeedByDealerCode) {
ScmsaPosTransRollup scmsaPosTransRollupUpdateFlag = new ScmsaPosTransRollup();
modelMapper.map(scmsaPosTransRollupFeed, scmsaPosTransRollupUpdateFlag);
scmsaPosTransRollupUpdateFlag.setProcessedFlag("Y");
scmsaPosTransRollupUpdatedFlagList.add(scmsaPosTransRollupUpdateFlag);
}
return scmsaPosTransRollupUpdatedFlagList;
}
}
The StoreIdAssignmentService class contains the method "calculateStateForPosHourlyStTransaction" which calls some method in Factory class. When I debug as the junit test case , am not able to call that factory class method . What I am doing wrong here. Can anyone please suggest me.
You are mocking the factory:
#Mock
private StoreIdAssignmentFactory storeIdAssignmentFactory;
So you can't investigate the method createHourlyStEntryFromRollUp inside the factory, because the whole factory is mocked:
storeIdAssignmentFactory.createHourlyStEntryFromRollUp
If you trying to debug the createHourlyStEntryFromRollUp and the StoreIdAssignmentFactory is a #Component (or #Service), I recommend create a StoreIdAssignmentFactoryTest class test, use the #Autowired on it and #MockBean his dependencies.
Example:
#SpringBootTest
public class StoreIdAssignmentFactoryTest {
#Autowired
StoreIdAssignmentFactory factory;
#Test
public void testing() {
List<ScmsaPosTransRollup> list = factory.createHourlyStEntryFromRollUp(...);
//TODO asserts and etc
}
}
But this test is considered a integration test, because it load the whole spring context and beans related.
Another alternative is the (true) unit test. Use your constructor and not use #SpringBootTest, mock the dependencies (ModelMapper). This makes the test more fast and simple.
Example:
public class StoreIdAssignmentFactoryTest {
#Test
public void testing() {
ModelMapper mapper = mock(ModelMapper.class);
StoreIdAssignmentFactory factory = new StoreIdAssignmentFactory(mapper)
List<ScmsaPosTransRollup> list = factory.createHourlyStEntryFromRollUp();
//TODO asserts and etc
}
}
I am using Junit4 and Mockito for test cases, in the following code I am trying to mock a autowired object which throws null pointer exception inside the mocking class which means autowired object is not mocking properly
ContentDao.java
public class ContentDao {
#Autowired
private ConfigProperties configProperties;
public void fuction() {
int batchSize = configProperties.getBatchSize();
}
ConfigProperties.java
#ConfigurationProperties(ignoreUnknownFields = false, prefix = "cleanup")
public class ConfigProperties {
private int batchSize;
public int getBatchSize() {
return batchSize;
}
}
Trying to mock ConfigProperties.
#RunWith(MockitoJUnitRunner.class)
public class ContentDaoTest{
#InjectMocks
private ContentDao contentDao;
#Mock
private ConfigProperties configProperties;
#Test
public void functionTest(){
configProperties = mock(ConfigProperties.class);
when(configProperties.getBatchSize()).thenReturn(100);
ContentDao contentDao = new ContentDao();
contentDao.funtion();
}
funtion is called, but I get NPE in below line. Please help I am stuck here.
int batchSize = configProperties.getBatchSize();
If you set #Mock for configProperties, you should not mock again configProperties = mock(ConfigProperties.class);
In the same idea, as you set #InjectMocks for contentDao, you should not instantiate a new contentDao.
#RunWith(MockitoJUnitRunner.class)
public class ContentDaoTest {
#InjectMocks
private ContentDao contentDao;
#Mock
private ConfigProperties configProperties;
#Test
public void functionTest() {
Mockito.when(configProperties.getBatchSize()).thenReturn(100);
Assertions.assertThat(contentDao.getBatchSize()).isEqualTo(100);
}
}