【问题标题】:Mock Projection Result Spring Data JPA模拟投影结果 Spring Data JPA
【发布时间】:2017-11-13 06:13:37
【问题描述】:

我在我的 spring boot 项目中使用 spring data 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。

我的问题是如何模拟存储库的结果?那么应该返回什么?我的意思是如何为它创建投影实例和 setData?

【问题讨论】:

  • 创建一个实现接口的类,或者使用Mockito创建接口的mock实例。

标签: mockito spring-boot-test


【解决方案1】:

如果您想创建投影实例而不创建实现接口的类,可以使用 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

【讨论】:

  • 你错过了这部分ProjectionFactory factory = new SpelAwareProxyProjectionFactory();
  • 谢谢,我已经添加了。
【解决方案2】:

这是在 TEST 中模拟投影的最简单方法

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

    String getUrl() {
      return "url";
    }
}

【讨论】:

    【解决方案3】:

    我们通过以下方式实现了相同的东西

    首先mock了两类对象:

    @Mock
    private EntityManager em;
    
    @Mock
    private DemoProjectRepo demoProjectRepo;
    

    我的demoProjectRepo.findByAll 返回List&lt;DemoProjectDevices&gt;

    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);
    

    【讨论】:

      【解决方案4】:

      作为对 Nis 回答的补充:

      如果界面没有setter,可以用地图初始化投影:

      ProjectionFactory factory = new SpelAwareProxyProjectionFactory();
      Map<String, Object> map = Map.of("title", "theTitle", "url", "theUrl")
      VeryBasicProjection projection = factory.createProjection(VeryBasicProjection.class, map);
      

      【讨论】:

      • 不编译
      【解决方案5】:

      在您的投影界面中,您需要为您拥有 getter 的值添加 setter。

      因此,当您有一个实现投影接口的具体类时,您可以将值添加到该类中,这样您就可以得到以下内容:

          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));
      
          }
      

      【讨论】:

      • 你不需要用setter方法污染投影界面。相反,在您的实现类中定义它们。
      猜你喜欢
      • 1970-01-01
      • 2021-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-25
      • 2018-03-05
      相关资源
      最近更新 更多