Результат фиктивной проекции Spring Data JPA

Я использую весенние данные jpa в своем проекте весенней загрузки.

Я запускаю запрос JPQL и использую проекцию для сохранения результата запроса. Моя проекция:

public interface VeryBasicProjection {
    String getTitle();
    String getUrl();
}

Мой сервис, вызывающий эту проекцию:

public List<VeryBasicDTO> getLatestData(int limit){

        // Pageable for Limit
        Pageable pageable = new PageRequest(0, limit);

        // Get Data from DB
        List<VeryBasicProjection> latestData = tableRepository.getLatestData("live", 2,pageable);
        List<VeryBasicDTO> responseDTO = new ArrayList<>();

        // Map Projection to DTO
        for(VeryBasicProjection veryBasicProjection : latestData){
            VeryBasicDTO veryBasicDTO = new VeryBasicDTO();
            veryBasicDTO.buildDTO(veryBasicProjection);
            responseDTO.add(veryBasicDTO);
        }

        return responseDTO;
    }

Теперь я хочу протестировать эту службу с помощью Mockito (модульный тестовый пример). Я издеваюсь над вызовом репозитория, используя when и thenReturn.

Мой вопрос: как мне издеваться над результатом репозитория? Что должно быть в thenReturn? Я имею в виду, как мне создать экземпляр проекции и установить для него данные?


person Ankit Bansal    schedule 13.11.2017    source источник
comment
Создайте класс, реализующий интерфейс, или используйте Mockito для создания фиктивных экземпляров интерфейса.   -  person JB Nizet    schedule 13.11.2017


Ответы (5)


Если вы хотите создать экземпляр своей проекции без создания класса, реализующего интерфейс, вы можете использовать SpelAwareProxyProjectionFactory.

import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;

...
ProjectionFactory factory = new SpelAwareProxyProjectionFactory();
VeryBasicProjection projection = factory.createProjection(VeryBasicProjection.class);
projection.setTitle("theTitle");
projection.setUrl("theUrl");

Вам также необходимо добавить сеттеры в вашу проекцию:

public interface VeryBasicProjection {
    String getTitle();
    String getUrl();
    void setTitle(String title);
    void setUrl(String url);
}

Источник: https://github.com/spring-projects/spring-data-examples/blob/master/rest/projections/src/test/java/example/springdata/rest/projections/SimpleProjectionTests.java

person Nis    schedule 06.09.2018
comment
вы пропустили эту часть ProjectionFactory factory = new SpelAwareProxyProjectionFactory(); - person Mohammed Rafeeq; 26.09.2019
comment
Спасибо, я добавил это. - person Nis; 16.01.2020

Это самый простой способ имитировать проекции в TEST.

VeryBasicProjection VeryBasicProjection = new VeryBasicProjection() {
   String getTitle() {
    return "Title";
   }

    String getUrl() {
      return "url";
    }
}
person IZI_SL    schedule 19.09.2019

Мы реализовали то же самое ниже

Сначала издевался над двумя типами объектов:

@Mock
private EntityManager em;

@Mock
private DemoProjectRepo demoProjectRepo;

Мой demoProjectRepo.findByAll возвращает List<DemoProjectDevices>

DemoProjectDevices device1 = new DemoProjectDevices();
device1.setAcctNbr("2365897412236589");
device1.setdeviceSeq(new BigDecimal(1));
device1.setCrteTms("2017-07-29 01:21:44.910807");
List<DemoProjectDevices> demoProjectDevices = new ArrayList<DemoProjectDevices>();
demoProjectDevices.add(device1);

Для макета, когда и тогда:

Mockito.when(demoProjectRepo.findByAll("2365897412236589", em)).thenReturn(demoProjectDevices);
person Milan Thummar    schedule 13.11.2017

В вашем интерфейсе проекции вам нужно добавить сеттеры для значений, для которых у вас есть геттеры.

Поэтому, когда у вас есть конкретный класс, реализующий интерфейс проекции, вы можете добавить значения в этот класс, чтобы у вас могло быть что-то вроде этого:

    public interface VeryBasicProjection {
        String getTitle();
        String getUrl();
        void setTitle(String title);
        void setUrl(String url);
    }

    public class VeryBasicProjectionImpl implements VeryBasicProjection{
        //add implementing methods
    }

    ////

    @Mock
    Repository tableRepo;

    @InjectMocks
    ClassUnderTest c;

    @Test
    public void test(){

        // Pageable for Limit
        Pageable pageable = new PageRequest(0, limit);

        VeryBasicProjection vbp = new VeryBasicProjectionImpl();
        // add data to object here using the setters

        List<VeryBasicProjection> projList = new ArrayList<>()
        //add objects created

        when(tableRepo.getLatestData("live", 2, pageable)).thenReturn(projList));

    }
person dg100500    schedule 11.05.2018
comment
Вам не нужно загрязнять интерфейс проекции сеттерными методами. Вместо этого определите их в своем классе реализации. - person Mark Norman; 02.04.2019

В дополнение к ответу Ниша:

Если в интерфейсе нет сеттеров, проекцию можно инициализировать картой:

ProjectionFactory factory = new SpelAwareProxyProjectionFactory();
Map<String, Object> map = Map.of("title", "theTitle", "url", "theUrl")
VeryBasicProjection projection = factory.createProjection(VeryBasicProjection.class, map);
person Fabian    schedule 23.06.2021
comment
Не компилируется - person Zafar Nasim; 29.07.2021