You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Groovy Spock测试中Mock ProductCategory的findAll方法失败

问题描述

我有一个用于关联Product与ProductCategory的服务类,依赖MongoDB的ProductCategoryRepository。该仓库自定义了一个接收productIds列表的findAll方法,用于批量查询对应的ProductCategory。但在Spock测试中Mock这个findAll方法时执行失败,抛出异常。

服务类代码

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;


@Service
@Slf4j
public class ProductsLinkService {

    private final ProductCategoryRepository productCategoryRepository;

    @Autowired
    public ProductsLinkService(ProductCategoryRepository productCategoryRepository) {
        this.productCategoryRepository = productCategoryRepository;
    }

    public List<Product> process(List<Product> products) {
        if (ObjectUtils.isEmpty(products)) {
            return new ArrayList<>();
        }
        List<Long> productIds = MappingUtilityFunctions.retrieveIdsForDepartments(products);
        List<ProductCategory> productCategories = productCategoryRepository.findAll(productIds);
        return linkProductsWithCategory(products,productCategories);
    }

    private List<Product> linkProductsWithCategory(List<Product> products, List<ProductCategory> productCategories) {
        //...
    }
}

Repository代码

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;


@Repository
public interface ProductCategoryRepository extends MongoRepository<ProductCategory, Long> {

    @Query(value = "{ '_id' : {'$in' : ?0 } }")
    List<ProductCategory> findAll(List<Long> productIds);
}

Spock测试代码

class ProductsLinkServiceSpec extends Specification {

    ProductCategoryRepository productCategoryRepository = Mock()
    List<Long> productIds =  [11L, 22L, 33L]
    ProductsLinkService productsLinkService

    def setup(){
        productsLinkService = new ProductsLinkService(productCategoryRepository)
    }

    def'Associating products with their product categories should be successful'(){
        given:
         List<Product> products = ....
         List<ProductCategory> productCategories = ...

         // 此处抛出异常
         productCategoryRepository.findAll(productIds) >> productCategories
                 
        when:

          def productsWithCategories = productsLinkService.process(products)
          then:
            // 断言
       
    }
}

异常信息

groovy.lang.MissingMethodException: No signature of method: java.util.ArrayList.call() is applicable for argument types: () values: []
Possible solutions: tail(), tail(), wait(), any(), last(), tails()
at com.adx.batch.linking.ProductsLinkServiceSpec.Associating products with their product categories should be successful(ProductsLinkServiceSpec.groovy:25)
原因与解决方案

问题根源

自定义的findAll(List<Long>)方法和MongoRepository自带的无参findAll()方法签名冲突,触发了Groovy的语法歧义:
Groovy允许对列表实例使用()语法(比如list(0)等价于list.get(0)),当你写productCategoryRepository.findAll(productIds)时,Groovy会误解析为:

  1. 调用无参的productCategoryRepository.findAll(),得到一个List<ProductCategory>实例
  2. 尝试对这个列表调用call(productIds),也就是用productIds作为索引取值,而ArrayList并没有call()方法,因此抛出异常。

解决方案

方案1:重命名自定义方法(推荐)

直接修改Repository中的方法名,避免和父接口方法冲突:

@Repository
public interface ProductCategoryRepository extends MongoRepository<ProductCategory, Long> {
    @Query(value = "{ '_id' : {'$in' : ?0 } }")
    List<ProductCategory> findAllByProductIds(List<Long> productIds);
}

同时更新服务类的调用代码:

List<ProductCategory> productCategories = productCategoryRepository.findAllByProductIds(productIds);

测试代码中的Mock语句也对应修改:

productCategoryRepository.findAllByProductIds(productIds) >> productCategories

方案2:明确指定方法参数类型

如果不想修改方法名,可以在Spock的Mock语句中通过类型约束消除歧义:

// 方式1:使用参数类型约束
productCategoryRepository.findAll(_ as List<Long>) >> productCategories

// 方式2:强制转换参数类型
productCategoryRepository.findAll((List<Long>) productIds) >> productCategories

内容的提问来源于stack exchange,提问作者BreenDeen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 18:35:15