How to mock service in service test? - java

I try write service test, for example, I have this ExamServiceImpl:
#Service
public class ExamServiceImpl implements ExamService {
#Autowired
private final SubjectService subjectService;
private final ScoreDAO scoreDAO;
#Autowired
public ExamServiceImpl(ScoreDAO scoreDAO) {
this.scoreDAO = scoreDAO;
}
#Override
public ResponseModel insertScore(RequestModel request) throws IOException {
List<TeacherModel> teacher = teacherDAO.getNameList(request);
List<StudentModel> student = studentDAO.findStudentList(teacher.get(0).getName, request.getStudentScore);
String nameStudent = student.get(0).getFirstName() + student.get(0).getLastName();
SubjectModel subject = subjectService.getNameSubject(request, nameStudent);
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");
TeacherModel resTeacher = new Teacher()
resTeacher.setName("test Teacher");
StudentModel studentData = new Student();
student.setFirstName("firstname");
studebt.setLastName("lastname");
Mockito.when(teacherDAO.getNameList(new RequestModel())).thenReturn(resTeacher);
Mockito.when(studentDAO.findStudentList(anyString(), anyString())).thenReturn(studentData);
Mockito.when(subjectService.getNameSubject(Mokito.any(RequestModel.class), anyString())).thenReturn(resFromSubject);
Mockito.when(scoreDAO.insert(Mokito.any(ScoreModel.class)).thenReturn(1);
int resultTest = examService.insertScore(new RequestModel());
assertSame(ex, 1);
}
But output resultTest is error. I try debugger, I found
Mock studentDAO.findStudentList() return null >> mock is not working.
When I close code + test teacherDAO and studentDAO for test mock subjectService >> mock subjectService is not working too. (I not sure mock service should be use #Autowired or #MorkBean)
Please, could you help write me test methods? I covered with tests more simple other services.
Thank you!

You can find demo application in this blog
[https://blog.joshsoftware.com/2020/05/27/introduction-to-mockito-unit-testing-framework/][1]

Related

SpringBoot Mockito: when..thenReturn giving an exception

So, currently, I'm testing on a Service class
This is my ConvertService.java
#Service
public class ConvertService {
private final NetworkClient networkClient; //NetworkClient is a Service too
private final ConvertUtility convertUtility;
public ConvertService(Network networkClient) {
convertUtility = ConvertFactory.of("dev", "F");
this.networkClient = networkClient
}
public Response convert(Request request) {
User user = networkClient.getData(request.getId()); //User is POJO class
Context context = convertUtility.transform(request.getToken()) //getToken returns a String
//Context is a normal Java
}
}
This is my ConvertServiceTest.java
#SpringBootTest
#RunWith(MockitoJunitRunner.class)
class ConvertServiceTest {
#MockBean
private NetworkClient networkClient;
#Mock
ConvertUtility convertUtility;
private ConvertService convertService;
#BeforeEach
void setUp() {
convertService = new ConvertService(networkClient);
}
private mockMethod() {
Request request = Request(1000);
User user = new User("user1");
Context context = new Context();
when(networkClient.getData(anyLong())).thenReturn(user);
when(convertUtility.transform(any(String.class)).thenReturn(context);
Response response = convertService.convert(request); //it throws me an exception here
}
}
convertService.convert(request); throws an exception
pointing inside convertUtility.transform(request.getToken())
I'm not sure why it's processing everything from transform method, when I wrote
when(convertUtility.transform(any(String.class)).thenReturn(context);
Can anyone please help?
EDIT: ConvertUtility is a read-only library
Inside your public constructor, you're using a static factory method to get an instance of the ConvertUtility. You'd have to mock the static ConvertUtility.of() method to work with a mock during your test.
While Mockito is able to mock static methods, I'd recommend refactoring (if possible) your class design and accepting an instance of ConvertUtility as part of the public constructor:
#Service
public class ConvertService {
private final NetworkClient networkClient; //NetworkClient is a Service too
private final ConvertUtility convertUtility;
public ConvertService(Network networkClient, ConvertUtility convertUtility) {
this.convertUtility = convertUtility
this.networkClient = networkClient
}
}
With this change, you can easily mock the collaborators of your ConvertService when writing unit tests:
#ExtendWith(MockitoExtension.class)
class ConvertServiceTest {
#Mock
private NetworkClient networkClient;
#Mock
private ConvertUtility convertUtility;
#InjectMocks
private ConvertService convertService;
#Test // make sure it's from org.junit.jupiter.api
void yourTest() {
}
}

Unit Test could not pass due to constructur error

I am struggling at wrting unit test, when I test my code block, it says : constructor error
my code below;
#Component
public class CodeConfigBuilder {
#Value("${promoConfig.prefix.length}")
private Integer prefixLength;
public void validateRequestAndSetDefaults(PromoRequest promoRequest) {
prefixAndPostFixControlAccordingToLength(promoRequest);
}
private void prefixAndPostFixControlAccordingToLength(PromoRequest promoRequest) {
if (promoRequest.getPostfix() != null) {
int lengthControl = prefixLength + promoRequest.getPostfix().length();
if (lengthControl >= promoRequest.getLength()) {
throw new BadRequestException(Constant.ClientConstants.THE_SUM_OF_PREFIX_AND_POSTFIX_CAN_NOT_BE_GREATER_THAN_LENGHT);
}
}
}
public void validateRequestAndSetDefaults(PromoRequest promoRequest) {
prefixAndPostFixControlAccordingToLength(PromoRequest promoRequest)
}
my yml configuration below;
#========= Promo Config ========== #
promoConfig:
prefix:
length: 3
my service below;
public void validateRequest(PromoRequest promoRequest) {
codeConfigBuilder.validateRequestAndSetDefaults(promoRequest);
}
I have a created PropertySourceResolver class
#Value("${promoGenerationConfig.prefix.length}")
private Integer prefixLength;
and my test class below;
#ExtendWith(SpringExtension.class)
class CodeConfigBuilderTest {
private final PromonRequest promoRequest;
private final PropertySourceResolver propertySourceResolver;
private final PromoService promoService;
private final Request request;
public CodeConfigBuilderTest(PromonRequest promoGenerationRequest, PropertySourceResolver propertySourceResolver, PromoService promoService, Request request) {
this.PromonRequest = PromonRequest ;
this.propertySourceResolver = propertySourceResolver;
this.promoService = promoService;
this.request = request;
}
#Test
void prefixAndPostFixControlAccordingToLength() {
promoService.validateRequest(promoRequest);
int lengthControl = propertySourceResolver.getPrefixLength() + promoRequest.getPostfix().length();
Assertions.assertTrue(true, String.valueOf(lengthControl));
}
I have tried many things but my code does not pass the test it says "org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter"
any help, thank you
I'm not 100% but IMHO you can't use constructor injection in unit tests.
Use this instead:
#SpringBootTest
class CodeConfigBuilderTest {
#Autowired
private PromonRequest promoRequest;
#Autowired
private PropertySourceResolver propertySourceResolver;
#Autowired
private PromoService promoService;
#Autowired
private Request request;

Test a controller with Junit?

I had some trouble setting up unit test with my spring boot application. My main issue is with the "model" object that's needed in my controller, but I can't find a way to recreate it in my test, which is required to use my function.
here are the function I want to test
#Controller
public class AjoutAbscenceControler {
#Autowired
private AbsenceRepository absenceRepository;
#RequestMapping(value = { "/addAbsence" }, method = RequestMethod.GET)
public String showAddAbsencePage(Model model) {
Absence absence = new Absence();
model.addAttribute("Absence", absence);
return "addAbsence";
}
#RequestMapping(value = { "/addingAbsence" }, method = RequestMethod.POST)
public String saveAbsence(Model model, #ModelAttribute("absence") Absence absence) {
if (absence.getName() != null && absence.getName().length() > 0) {
absenceRepository.save(absence);
}
return "redirect:/userList";
}
}
I did try something like that
#RunWith(MockitoJUnitRunner.class)
public class AjoutAbscenceControlerTest {
#Mock
VacationRepository vacationRepository;
#Mock
CategoryRepository categoryRepository;
#InjectMocks
AjoutAbscenceControler controler;
public MockMvc mockMvc;
#Before
public void setUp() throws Exception{
mockMvc = MockMvcBuilders.standaloneSetup(controler).build();
}
#Test
public void showAddAbsencePagetest() {
AjoutAbscenceControler ajoutAbscenceControler =new AjoutAbscenceControler();
assertEquals("addAbsence",ajoutAbscenceControler.showAddAbsencePage(controler));
}
}
but I don't find any way to create a springfarmwork.ui.Model
If you're testing the logic of your controller you probably shouldn't create a Model object, but mock it, and verify the interactions against it:
#Mock
private Model model;
#Test
public void showAddAbsencePagetest() {
// Should probably be initialized in a #Before method,
// Initialized here for clarity only
AjoutAbscenceControler ajoutAbscenceControler = new AjoutAbscenceControler();
assertEquals("addAbsence", ajoutAbscenceControler.showAddAbsencePage(model));
Mockito.verify(model).addAttribute(eq("Absence"), any(Absence.class));
}

NullPointer when call entity Manager

I try to write some programme using Java, Hibernate and Spring. I see NullPointerException when I call the SQL query. I tried perhaps every samples of code on the internet, but I don't know how to do this. How can I solve it? This is my sample code. There is my full code of programme: https://github.com/lukasz-chojn/films_database/tree/master/src/main/java/Films
#Controller
public class DataFromUserController {
private FilmDaoImpl filmDaoImpl = new FilmDaoImpl();
private DirectorDaoImpl directorDaoImpl = new DirectorDaoImpl();
private Locale locale = Locale.getDefault();
private Scanner sc = new Scanner(System.in).useLocale(locale);
public FilmDs collectData() {
//....
filmDaoImpl.insert(film);
directorDaoImpl.insert(director);
return film;
}
private String collectTitle() {
System.out.print("Podaj tytuł filmu: ");
String tytul = sc.nextLine();
List<String> existingEntry = filmDaoImpl.existingTitle();
if (existingEntry.contains(tytul)) {
System.out.println("Tytuł jest już w bazie. Podaj inny");
return collectTitle();
}
if (tytul.isEmpty()) {
System.out.println("Tytuł nie może być pusty. Podaj go");
return collectTitle();
}
return tytul;
}//......
}
#Service
#Transactional
public class FilmDaoImpl implements FilmDAO {
#PersistenceContext
private EntityManager entityManager;
//......
#Override
#SuppressWarnings("unchecked")
public List<String> existingTitle() {
List<String> titleInTheDatabase;
// here is NPE
return titleInTheDatabase = entityManager.createQuery("SELECT film.tytul FROM FilmDs film").getResultList();
}
//....
}
You're creating instances on your own instead of letting spring inject it for you which is why you're losing all the dependencies like entitymanager, etc. change your DataFromUserController
#Controller
public class DataFromUserController {
#Autowired
private FilmDAO filmDao;
#Autowired
private DirectorDAO directorDao;
.....
}

Testing a controller with an auto wired component is null when calling the controller from a test case

I have a controller
#RestController
public class Create {
#Autowired
private ComponentThatDoesSomething something;
#RequestMapping("/greeting")
public String call() {
something.updateCounter();
return "Hello World " + something.getCounter();
}
}
I have a component for that controller
#Component
public class ComponentThatDoesSomething {
private int counter = 0;
public void updateCounter () {
counter++;
}
public int getCounter() {
return counter;
}
}
I also have a test for my controller.
#RunWith(SpringRunner.class)
#SpringBootTest
public class ForumsApplicationTests {
#Test
public void contextLoads() {
Create subject = new Create();
subject.call();
subject.call();
assertEquals(subject.call(), "Hello World 2");
}
}
The test fails when the controller calls something.updateCounter(). I get a NullPointerException. While I understand it's possible to add #Autowired to a constructor I would like to know if there is anyway to do this with an #Autowired field. How do I make sure the #Autowired field annotation works in my test?
Spring doesn't auto wire your component cause you instantiate your Controller with new not with Spring, so Component is not instatntiated
The SpringMockMvc test check it correct:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class CreateTest {
#Autowired
private WebApplicationContext context;
private MockMvc mvc;
#Before
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.build();
}
#Test
public void testCall() throws Exception {
//increment first time
this.mvc.perform(get("/greeting"))
.andExpect(status().isOk());
//increment secont time and get response to check
String contentAsString = this.mvc.perform(get("/greeting"))
.andExpect(status().isOk()).andReturn()
.getResponse().getContentAsString();
assertEquals("Hello World 2", contentAsString);
}
}
The #Autowired class can be easily mocked and tested with MockitoJUnitRunner with the correct annotations.
With this you can do whatever you need to do with the mock object for the unit test.
Here is a quick example that will test the Create method call with mocked data from ComponentThatDoesSomething.
#RunWith(MockitoJUnitRunner.class)
public class CreateTest {
#InjectMocks
Create create;
#Mock
ComponentThatDoesSomething componentThatDoesSomething;
#Test
public void testCallWithCounterOf4() {
when(componentThatDoesSomething.getCounter()).thenReturn(4);
String result = create.call();
assertEquals("Hello World 4", result);
}
}
Use Mockito and inject a mock that you create. I would prefer constructor injection:
#RestController
public class Create {
private ComponentThatDoesSomething something;
#Autowired
public Create(ComponentThatDoesSomething c) {
this.something = c;
}
}
Don't use Spring in your Junit tests.
public CreateTest {
private Create create;
#Before
public void setUp() {
ComponentThatDoesSomething c = Mockito.mock(ComponentThatDoesSomething .class);
this.create = new Create(c);
}
}

Categories