【问题标题】:why mocking mongotemplate.aggregate() returns NullPointerException [Spring Boot Mockito]为什么模拟 mongotemplate.aggregate() 返回 NullPointerException [Spring Boot Mockito]
【发布时间】:2026-01-06 20:35:01
【问题描述】:

如何模拟mongoTemplate.aggregation().getUniqueMappedResults()

为什么在RepoClass中返回NullPointerException

mongoTemplate.aggregate(aggregation, COLLECTION_NAME,ScreenDetailsEntity.class);

我是 Spring 新手,第一次编写测试用例。我非常疲倦。 请帮忙。提前致谢。

RepoTestClassTest函数:

  @Test
  public void testValidGetScreenDetails() {
    ReflectionTestUtils.setField(
        screenDetailsRepoService, "screenFields",
        ClassUtil.getFieldName(ScreenDetailsEntity.class));
    Aggregation aggregation1 = Aggregation.newAggregation(
        match(where(PAGE).is("Bookings")),
        project(ClassUtil.getFieldName(ScreenDetailsEntity.class)),
        limit(1)
    );

    MongoTemplate mongoTemplate = Mockito.mock(MongoTemplate.class);
    Aggregation aggregation = Mockito.mock(Aggregation.class);
    ScreenDetailsEntity screenDetailsEntity = Mockito.mock(ScreenDetailsEntity.class);
    AggregationResults<ScreenDetailsEntity> aggregationResultsMock = Mockito
        .mock(AggregationResults.class);
    Mockito.when(aggregationResultsMock.toString()).thenReturn(new String());
    Mockito.doReturn(aggregationResultsMock).when(mongoTemplate).aggregate(aggregation1, COLLECTION_NAME, ScreenDetailsEntity.class);

    Mockito.doReturn(screenDetailsEntity).when(aggregationResultsMock).getUniqueMappedResult();
    screenDetailsRepoService.getScreenDetails(
        "Bookings", "Web8", "List/View", "en", 45429, 121);
  }

回购类:

public class ScreenDetailsRepoService {

  @Autowired
  private MongoTemplate mongoTemplate;

  private String[] screenFields;

  @PostConstruct
  public void init() {
    screenFields = ClassUtil.getFieldName(DetailsEntity.class);
  }

  public ScreenDetailsEntity getScreenDetails(final @NonNull String page,
      final @NonNull String client, final String module,
      final String locale, final Integer hotelId, final Integer countryId
  ) throws NoDataFoundException {
    ScreenDetailsEntity screenDetailsEntity;
    Aggregation aggregation = newAggregation(
        match(where(PAGE).is(page)),
        project(screenFields),
        limit(1)
    );
    long t1 = System.currentTimeMillis();
    screenDetailsEntity = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, ScreenDetailsEntity.class).getUniqueMappedResult();
    log.info(
        "DB Query: ScreenDetailsRepoService : getScreenDetails - Time taken for db requests : {} milliseconds",
        (System.currentTimeMillis() - t1));
    if (screenDetailsEntity == null) {
      log.error(
          "ScreenDetailsRepoService::getScreenDetails - No data found for for page {} ,module {}, locale {}, hotel {}, country {}",
          page, module, locale, hotelId, countryId);
      throw new NoDataFoundException("No data found");
    }
    return screenDetailsEntity;
  }

【问题讨论】:

    标签: java mongodb spring-boot mockito aggregation


    【解决方案1】:

    我最好的猜测是模拟设置方法中的Aggregation 参数

    Mockito.doReturn(aggregationResultsMock).when(mongoTemplate).aggregate(aggregation1, COLLECTION_NAME, ScreenDetailsEntity.class);
    

    不等于在getScreenDetails 中调用mongoTemplate.aggregate 中的实际值。 Mockito 使用equals 方法检查参数是否匹配,如果没有找到匹配的模拟设置,则默认返回null

    作为第一个测试,您可以尝试模拟任何聚合参数的方法。例如

    Mockito.doReturn(aggregationResultsMock).when(mongoTemplate).aggregate(Mockito.any(Aggregation.class), Mockito.eq(COLLECTION_NAME), Mockito.eq(ScreenDetailsEntity.class));
    

    这样您可以检查是否是聚合参数导致了问题。

    那么你应该确保Aggregation类的equalshashCode方法被正确实现。

    【讨论】:

    • ********* testValidGetScreenDetails 中的聚合值******** Mock for Aggregation, hashCode: 1330912871
    • getScreenDetails 中的聚合值:{ "aggregate" : "collection", "pipeline" : [{ "$match" : { "page" : "Bookings"}} ,{“$project”:{“page”:1,“module”:1,“locale”:1,“resource_id”:1,{“$sort”:{“order”:1}},{“$限制”:{“$numberLong”:“1”}}]}
    • 不知道现在该做什么。请进一步帮助。
    【解决方案2】:

    尝试使用注释,创建一个 MongoTemplate 模拟并使用 InjectMock 注释将其注入 ScreenDetailsRepoService

    @Mock
    private MongoTemplate mongoTemplate;
    
    @InjectMock
    private ScreenDetailsRepoService screenDetailsRepoService;
    

    【讨论】:

      【解决方案3】:

      每当您模拟任何方法时,以下是两个重要的考虑因素,

      1. 模拟方法的给定参数可以是您的代码中的null。在这种情况下any() 方法不起作用,您应该使用nullable() 方法
      2. 模拟方法的给定参数类型相同。建议提供相同类型的参数,否则使用通用模拟。

      如果你正确地遵循这些,你可以在 Spring 框架中使用方法。在您的情况下,下面的模拟应该可以正常工作。

      doReturn(someResult)
          .when(mongoTemplate)
          .aggregate(Mockito.nullable(Aggregation.class), Mockito.nullable(String.class), Mockito.<Class<?>> any());
      

      【讨论】:

        【解决方案4】:

        我遇到了与您完全相同的问题,我通过从 aggregate 方法返回的任何内容中模拟 AggregationResults 来解决它,然后我模拟了我模拟的 AggregationResults 实例的 getMappedResults() 方法。在你的情况下,我想你需要模拟getUniqueMappedResults(),因为这是你感兴趣的。

        这是我的代码的 sn-p,我就是这样做的:

                    // Previously, I have created a List<MyEntity> for testing, that I assigned to a variable called testEntities.
                    @SuppressWarnings("unchecked")
                    final AggregationResults<MyEntity> mockResults = (AggregationResults<MyEntity>) mock(
                            AggregationResults.class
                    );
                    when(mockResults.getMappedResults()).thenReturn(testEntities);
                    when(operations.aggregate(any(Aggregation.class), anyString(), eq(MyEntity.class)))
                            .thenReturn(mockResults);
                   
                    // From here, whenever you call operations.aggregate(...).getMappedResults(), the testEntities list will be retrieved, no NullPointerException given.
        

        【讨论】:

          最近更新 更多