Mockito: как имитировать автоматическую переменную во время тестирования

Я тестирую свое веб-приложение с помощью JUnit и Mockito. На данный момент я пытаюсь написать тестовые примеры для уровня обслуживания после завершения уровня DAO. Это мой тестовый пример:

package it.********.testService;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

import static org.mockito.Mockito.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.assertj.core.api.Assertions.*;

import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;

import it.********.constants.EasycareEnumTypes.ActivityType;
import it.********.dao.interf.AccountDAOInterface;
import it.********.dao.interf.CareTeamDAOInterface;
import it.********.dao.interf.DeviceDAOInterface;
import it.********.dao.interf.ObservationDAOInterface;
import it.********.dto.DeviceDTO;
import it.********.dto.ObservationDTO;
import it.********.exception.ECForbiddenException;
import it.********.mapper.DeviceMapper;
import it.********.mapper.ObservationMapper;
import it.********.model.Account;
import it.********.model.Device;
import it.********.model.Observation;
import it.********.service.DeviceService;
import it.********.service.ObservationService;
import it.********.testConf.MockDAOUtils;
import it.********.testConf.MockDTOUtils;
import it.********.testConf.TestContext;
import it.********.utilities.DatetimeUtils;
import it.********.utilities.SessionVariable;

@ContextConfiguration(classes = {TestContext.class})
@ComponentScan({"it.********.service"})
public class ObservationServiceTest extends AbstractTransactionalJUnit4SpringContextTests {

    @Autowired
    private MockDAOUtils mockDAOUtils;

    @Mock
    SessionVariable sessionVariable;

    @Mock
    private ObservationDAOInterface observationDAOMock;

    @Mock
    private AccountDAOInterface accountDAOMock;

    @Mock
    private CareTeamDAOInterface careTeamDAOMock;

    @Spy
    private ObservationMapper mapper;

    @InjectMocks
    private ObservationService service;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    /**
     * {getObservationList}
     * 
     * [account]
     * -------------------------------------------------------------------------------------------------------
     * | id   | enabled | locked | account_expired | password_expired | data_handling | role                 |
     * -------------------------------------------------------------------------------------------------------
     * | 1000 | 1       | 0      | 0               | 0                | 1             | patient              |  targetAccount : valid patient account
     * | 1001 | 1       | 0      | 0               | 0                | 1             | general_practitioner |  callerAccount : medic in patient careteam
     * | 1002 | 1       | 0      | 0               | 0                | 0             | patient              |  targetAccount : invalid patient account
     * | 1003 | 1       | 0      | 0               | 0                | 1             | patient              |  callerAccount : patient with ID different from patientID
     * -------------------------------------------------------------------------------------------------------
     * 
     * [Observation]
     * ------------------------------------------------------------------------
     * | id | activity_type | medical_record_id | execution_date      | Note  |
     * ------------------------------------------------------------------------
     * | 1  | act_pressure  | 1                 | 2018-06-01 11:00:00 | Note1 |
     * | 2  | act_oximetry  | 1                 | 2018-06-01 14:00:00 | Note2 |
     * ------------------------------------------------------------------------
     * 
     */
    @Test
    public void test_case_u0048() throws Exception {

        // Taking method name
        String methodName = new Object() {
        }.getClass().getEnclosingMethod().getName();
        // Building test case file path
        String path = mockDAOUtils.getTc_path() + methodName + mockDAOUtils.getXml_ext();

        // Setting the test environment
        List<Account> accountList = mockDAOUtils.mockAccount(path);
        List<Observation> observationList = mockDAOUtils.mockObservation(path);
        List<ActivityType> activityTypeList = new ArrayList<ActivityType>();
        activityTypeList.add(ActivityType.act_pressure);
        activityTypeList.add(ActivityType.act_oximetry);
        Date startDate = mockDAOUtils.getFormat().parse("2018-06-01 00:00:00");
        Date endDate = mockDAOUtils.getFormat().parse("2018-06-01 23:59:59");


        // [RESULT CASE - VALID TARGET ACCOUNT / MEDIC CALLER ACCOUNT IN PATIENT CARE TEAM]
        Mockito.when(accountDAOMock.findByPersonId(1000L)).thenReturn(accountList.get(0));
        Mockito.when(careTeamDAOMock.isCareTeam(1000L, 1001L)).thenReturn(true);
        Mockito.when(sessionVariable.getTimezone()).thenReturn("GMT-8:00");
        System.out.println("[SV] = " + sessionVariable.getTimezone());
        Mockito.when(observationDAOMock.getListByMedRecIdAndActivityTypeAndDateRange(1L, activityTypeList, startDate, endDate)).thenReturn(observationList);
        List<ObservationDTO> observationDTOList = service.getObservationList(1000L, accountList.get(1), activityTypeList, startDate, endDate);

    }

}

Уровень обслуживания:

package it.********.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import it.********.constants.EasycareEnumTypes.ActivityType;
import it.********.constants.EasycareEnumTypes.ApplicationRole;
import it.********.dao.interf.AccountDAOInterface;
import it.********.dao.interf.CareTeamDAOInterface;
import it.********.dao.interf.ObservationDAOInterface;
import it.********.dto.ObservationDTO;
import it.********.exception.ECForbiddenException;
import it.********.exception.ECNotFoundException;
import it.********.mapper.ObservationMapper;
import it.********.model.Account;
import it.********.model.Observation;
import it.********.utilities.DatetimeUtils;
import it.********.utilities.SessionVariable;

@ComponentScan({"it.********.mapper","it.********.dao.impl"})
@Service
@Transactional
public class ObservationService {

    @Autowired
    ObservationDAOInterface observationDAO;

    @Autowired
    SessionVariable sessionVariable;

    @Autowired
    ObservationMapper observationMapper;

    @Autowired
    AccountDAOInterface accountDAO;

    @Autowired
    CareTeamDAOInterface careTeamDAO;

    /**
     * Provide the list of ObservationDTO of the patient included in the period and matching the list of types
     * 
     * @param patientId id of the patient
     * @param activityTypes list of activity types
     * @param startDate beginning of the period
     * @param endDate end of the period
     * @return the list of observations, eventually empty
     * 
     */

    @Transactional(readOnly=true)
    public List<ObservationDTO> getObservationList(long patientId, Account callerAccount, List<ActivityType> activityTypes, Date startDate, Date endDate){  

        // target permission check      
        Account targetAccount = accountDAO.findByPersonId(patientId);
        if (targetAccount == null) {
            throw new ECNotFoundException();
        } else if (!targetAccount.isValid()){
            throw new ECForbiddenException();
        } else if (targetAccount.getFirstApplicationRole() != ApplicationRole.patient) {
            throw new ECForbiddenException();
        }

        // caller permission check
        switch (callerAccount.getFirstApplicationRole()) {
            case general_practitioner:
            case medical_specialist:
                if (!careTeamDAO.isCareTeam(targetAccount.getId(), callerAccount.getId())) {
                    throw new ECForbiddenException();
                }
                break;
            case patient:
                if (targetAccount.getId() != callerAccount.getId()){
                    throw new ECForbiddenException();
                }
                break;
            default:
                throw new ECForbiddenException();       
        }

        List<Observation> observationList = observationDAO.getListByMedRecIdAndActivityTypeAndDateRange(targetAccount.getMedicalRecord().getId(), activityTypes, startDate, endDate);
        List<ObservationDTO> observationDTOList = new ArrayList<>();

        for(Observation item : observationList){
            observationDTOList.add(observationMapper.convertToDTO(item));
        }

        return observationDTOList;      
    }

}

Картограф:

package it.********.mapper;

import java.util.Map;
import java.util.TimeZone;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import it.********.constants.EasycareEnumTypes.ObservationExamType;
import it.********.constants.EasycareEnumTypes.ObservationParameterType;
import it.********.dto.ObservationDTO;
import it.********.dto.ScalarObservationDTO;
import it.********.dto.SignalObservationDTO;
import it.********.model.Observation;
import it.********.model.ObservationScalar;
import it.********.model.ObservationSignal;
import it.********.utilities.DatetimeUtils;
import it.********.utilities.SessionVariable;

@Component
public class ObservationMapper extends Mapper<ObservationDTO,Observation> {

    @Autowired
    SessionVariable sessionVariable;

    @Autowired
    ScalarObservationMapper scalarMapper;

    @Override
    public ObservationDTO convertToDTO(Observation entity) {
        ObservationDTO observationDTO = new ObservationDTO();
        observationDTO.setActivityType(entity.getActivityType());
        observationDTO.setActivityLabel(entity.getActivityType().getLabelCode());
        //observationDTO.setScheduleActivityId(entity.getScheduleActivity() != null ? entity.getScheduleActivity().getId() : null);
        observationDTO.setMedicalRecordId(entity.getMedicalRecord().getId());
        System.out.println("[SV] = " + sessionVariable.getTimezone());
        observationDTO.setExecutionDate(DatetimeUtils.dateToDatetimeISO8601(entity.getExecutionDate(),TimeZone.getTimeZone(sessionVariable.getTimezone())));
        observationDTO.setId(entity.getId());
        observationDTO.setNote(entity.getNote());

        for(ObservationScalar entityScalarObs : entity.getScalarObservationList()){
            ScalarObservationDTO scalarObsDTO = scalarMapper.convertToDTO(entityScalarObs);         
            observationDTO.getScalarObservationList().put(scalarObsDTO.getParameterType(), scalarObsDTO);
        }

        SignalObservationMapper signalMapper = new SignalObservationMapper();
        for(ObservationSignal entitySignalObs : entity.getSignalObservationList()){
            SignalObservationDTO signalObsDTO = signalMapper.convertToDTO(entitySignalObs);         
            observationDTO.getSignalObservationList().put(signalObsDTO.getType(), signalObsDTO);
        }

//      Hibernate.initialize(observationDTO.getScalarObservationList());
//      Hibernate.initialize(observationDTO.getSignalObservationList());
        return observationDTO;
    }

    @Override
    public Observation convertToEntity(ObservationDTO dto) {
        Observation observation = new Observation();
        observation.setActivityType(dto.getActivityType());
        observation.setExecutionDate(DatetimeUtils.stringToDate(dto.getExecutionDate()));
        observation.setNote(dto.getNote());

        for(Map.Entry<ObservationParameterType,ScalarObservationDTO> scalarObsDTO : dto.getScalarObservationList().entrySet()){
            if (scalarObsDTO.getValue() != null){//empty field
                observation.getScalarObservationList().add(scalarMapper.convertToEntity(scalarObsDTO.getValue()));
            }
        }

        SignalObservationMapper signalMapper = new SignalObservationMapper();
        for(Map.Entry<ObservationExamType,SignalObservationDTO> signalObsDTO : dto.getSignalObservationList().entrySet()){
            if (signalObsDTO.getValue() != null){
                observation.getSignalObservationList().add(signalMapper.convertToEntity(signalObsDTO.getValue()));
            }
        }       

        return observation;
    }

    @Override
    public void updateEntity(ObservationDTO dto, Observation entity) {
        // TODO Auto-generated method stub

    }

}

Моя проблема возникает при попытке протестировать метод «getObservationList» службы: все, что я высмеивал, работает хорошо, пока я не перейду к картографу, где я получил NullPointerException здесь

наблюдениеDTO.setExecutionDate (DatetimeUtils.dateToDatetimeISO8601 (entity.getExecutionDate (), TimeZone.getTimeZone (sessionVariable.getTimezone ())));

Я думаю, что sessionsioVariable имеет значение null из-за того, что он не инициализирован в моем тестовом контексте, поэтому я пытаюсь издеваться над некоторыми вещами, чтобы позволить мне иметь действительную переменную сеанса (содержимое в данный момент не важно) ничего не меняя в Service и Mapper.

Заранее спасибо! До свидания!

Вы проводите интеграционное тестирование?

CodeMonkey 28.09.2018 19:27

Похоже, вы пытаетесь имитировать Spring управляемые бобы. Посмотрите @MockBean на spring-test

shinjw 28.09.2018 19:33
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
2
1 648
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Аннотируйте переменную с помощью @Mock и имитируйте вызовы функций с помощью Mockito.when ().

когда (наблюдениеDAO.getStringX ()). thenReturn ("stringx");

Картографа нет в DAO, поэтому я не могу этого сделать!

Lubron 28.09.2018 19:28
Ответ принят как подходящий

Я считаю, что причина, по которой sessionVariable является нулевым, даже если вы явно насмехаетесь над ним, заключается в том, что ObservationMapper mapper имитируется с использованием @Spy. В отличие от @Mock, @Spy создает экземпляр макета объекта, но все, что упоминается внутри, имеет значение null, если вы явно не вводите в него макеты.

Решение 1:

@Mock
SessionVariable sessionVariable;

@Mock
ScalarObservationMapper scalarMapper;

@Spy
@InjectMocks
private ObservationMapper mapper;

Если это не сработает, вы можете попробовать использовать @Mock вместо @Spy, а затем издеваться над обеими службами (sessionVariable и scalarMapper) внутри класса ObservationMapper. Тем не менее, вы должны издеваться над обеими службами, поскольку вы используете их обе внутри метода convertToDTO.

Решение 2:

@Mock
SessionVariable sessionVariable;

@Mock
ScalarObservationMapper scalarMapper;

@Mock
private ObservationMapper mapper;

Другие вопросы по теме