当前位置: 首页 > 知识库问答 >
问题:

如何在Mockito中模拟部分字段

符学
2023-03-14

我正在为我的服务层编写单元测试。我的服务层有多个自动生成的字段。我想只模拟其中一个和其他初始化为自动驾驶。

服务接口

public interface ProductSupplierService {

    Map<String, List<? extends BaseDTO>> getProductSuppliers(Long productId, Long tenantId);

    ProductSupplierDTO addProductSupplier(Long productId, Long tenantId, ProductSupplierDTO productSupplierDTO);

    ProductSupplierDTO editProductSupplier(Long productId, Long supplierId, Long tenantId,
            ProductSupplierDTO productSupplierDTO);

    void deleteProductSupplier(Long productId, Long supplierId, Long tenantId);
}

服务实现

@Service
public class ProductSupplierServiceImpl implements ProductSupplierService {

    private MapperFacade mapper;

    @Autowired
    public void setMapperFactory(MapperFactory mapperFactory) {
        this.mapper = mapperFactory.getMapperFacade();
    }

    @Autowired
    private ProductRepository productRepository;

    @Autowired
    private ProductManager productManager;

    private static final Logger log = LoggerFactory.getLogger(ProductSupplierServiceImpl.class);

    @Override
    public Map < String, List << ? extends BaseDTO >> getProductSuppliers(Long productId, Long tenantId) {
        Product product = fetchProductByProductIdAndTenantId(productId, tenantId);
        ListResponse listResponse = new ListResponse();
        if (CollectionUtil.nonNullNonEmpty(product.getProductSuppliers())) {
            List < ProductSupplierDTO > productSupplierDTOS = new ArrayList < > (0);
            product.getProductSuppliers().stream().filter(Objects::nonNull)
                .forEach(productSupplier - > productSupplierDTOS
                    .add(productSupplier.toDTO(ProductSupplierDTO.class, mapper)));
            listResponse.addResponse("product_suppliers", productSupplierDTOS);
        }
        return listResponse.getResponse();
    }

    @Override
    public ProductSupplierDTO addProductSupplier(Long productId, Long tenantId, ProductSupplierDTO productSupplierDTO) {
        Product product = fetchProductByProductIdAndTenantId(productId, tenantId);
        ProductSupplier productSupplier = productSupplierDTO.toModel(ProductSupplier.class, mapper);
        if (product.getProductSuppliers().add(productSupplier)) {
            productManager.applyProductSupplier(product, tenantId, productSupplier);
            product.setModified(new Date());
            try {
                productRepository.save(product);
                Optional < ProductSupplier > savedProductSupplier = product.getProductSuppliers().stream()
                    .filter(Objects::nonNull)
                    .filter(ps - > ps.getSupplierId().equals(productSupplierDTO.getSupplierId())).findFirst();
                if (savedProductSupplier.isPresent()) {
                    return savedProductSupplier.get().toDTO(ProductSupplierDTO.class, mapper);
                } else {
                    throw new UnexpectedException();
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                throw new UnexpectedException();
            }
        } else {
            throw new BusinessValidationException("supplier already exists");
        }
    }

    @Override
    public ProductSupplierDTO editProductSupplier(Long productId, Long supplierId, Long tenantId,
        ProductSupplierDTO productSupplierDTO) {
        Product product = fetchProductByProductIdAndTenantId(productId, tenantId);
        Optional < ProductSupplier > productSupplierOptional = product.getProductSuppliers().stream()
            .filter(Objects::nonNull)
            .filter(productSupplier - > productSupplier.getSupplierId().equals(supplierId)).findFirst();
        if (productSupplierOptional.isPresent()) {
            ProductSupplier productSupplier = productSupplierOptional.get();
            if (Objects.nonNull(productSupplierDTO.getBuyPrice())) {
                productSupplier.setBuyPrice(productSupplierDTO.getBuyPrice());
            }
            if (Objects.nonNull(productSupplierDTO.isDefaultSupplier())) {
                if (productSupplierDTO.isDefaultSupplier()) {
                    product.getProductSuppliers().forEach(supplier - > supplier.setDefaultSupplier(false));
                    productSupplier.setDefaultSupplier(true);
                } else {
                    productSupplier.setDefaultSupplier(false);
                }
            }
            productSupplier.setModified(new Date());

            product.setModified(new Date());
            try {
                productRepository.save(product);
                return productSupplier.toDTO(ProductSupplierDTO.class, mapper);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                throw new UnexpectedException();
            }
        } else {
            throw new EntityNotFoundException(ProductSupplier.class, String.valueOf(supplierId));
        }
    }

    @Override
    public void deleteProductSupplier(Long productId, Long supplierId, Long tenantId) {
        Product product = fetchProductByProductIdAndTenantId(productId, tenantId);
        Optional < ProductSupplier > productSupplierOptional = product.getProductSuppliers().stream()
            .filter(Objects::nonNull)
            .filter(productSupplier - > productSupplier.getSupplierId().equals(supplierId)).findFirst();
        if (productSupplierOptional.isPresent()) {
            product.getProductSuppliers().remove(productSupplierOptional.get());
            product.setModified(new Date());
            try {
                productRepository.save(product);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                throw new UnexpectedException();
            }
        } else {
            throw new EntityNotFoundException(ProductSupplier.class, String.valueOf(supplierId));
        }
    }

    private Product fetchProductByProductIdAndTenantId(Long productId, Long tenantId) {
        Product product = productRepository.findByIdAndTenantId(productId, tenantId);
        if (Objects.nonNull(product)) {
            return product;
        } else {
            throw new EntityNotFoundException(Product.class, String.valueOf(productId));
        }
    }
}

测试类

@RunWith(MockitoJUnitRunner.class)
public class ProductSupplierServiceUnitTest {

    @Mock
    private ProductRepository productRepository;

    @Autowired
    @InjectMocks
    private ProductSupplierServiceImpl productSupplierService;

    @Test(expected = EntityNotFoundException.class)
    public void productNotFound() {
        Mockito.when(productRepository.findByIdAndTenantId(invalidProductId, tenantId)).thenReturn(null);
        productSupplierService.getProductSuppliers(invalidProductId, tenantId);
    }

    @Test
    public void getProductSuppliersSuccess() {

        initProduct();
        initProductSupplier();

        Set < ProductSupplier > productSuppliers = new HashSet < > (Collections.singletonList(productSupplierBuilder.get()));
        Product product = productBuilder.setProductSuppliers(productSuppliers).get();
        product.setId(validProductId);

        Mockito.when(productRepository.findByIdAndTenantId(validProductId, tenantId)).thenReturn(product);

        Map < String, List << ? extends BaseDTO >> result = productSupplierService.getProductSuppliers(validProductId,
            tenantId);
        Assert.assertEquals(result.size(), 1);
        Assert.assertTrue(result.containsKey("product_suppliers"));
    }

    @Test
    public void getProductSuppliersEmpty() {

        initProduct();
        initProductSupplier();

        Product product = productBuilder.setProductSuppliers(Collections.emptySet()).get();
        product.setId(validProductId);

        Mockito.when(productRepository.findByIdAndTenantId(validProductId, tenantId)).thenReturn(product);

        Map < String, List << ? extends BaseDTO >> result = productSupplierService.getProductSuppliers(validProductId,
            tenantId);

        Assert.assertTrue(result.isEmpty());
    }

}

我只想嘲笑productRepository字段,但不想嘲笑productManager

问题是productManager

是否可以自动初始化它们?就像它们在运行带有完全加载的上下文的Spring引导应用程序时被初始化一样。

共有2个答案

纪成礼
2023-03-14

要回答来自@Harsh yes的最后一条评论中的问题,您可以为测试配置上下文:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {ExampleTestConfiguration.class})

... 在ExampleTestConfiguration中的@ComponentScan中定义包含和排除的包

锺离珂
2023-03-14

如果是“产品经理”

@Spy
ProductManager productManager = new ProductManager();

@Spy
Mapper mapper = new Mapper();

Mockito知道注释为@InjectMocks的@Spy的对象。如果这些类有自己的@autowmed字段,这超出了Mockito的能力,常见的解决方案是使用SpringJUnit4ClassRunner,并在Spring上下文配置中使用Mockito:

<bean id="mockBean" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="some.real.bean.Class" />
</bean>
 类似资料:
  • 是模拟抽象类:,而是接口。这是失败点: 如何模拟这段代码?

  • 我使用的是Spring3.1.4.Release和Mockito1.9.5。在我的春季课上,我有: 我想为我的“Defaulturl”字段模拟一个值。请注意,我不想模拟其他字段的值--我希望保持这些字段的原样,只保留“Defaulturl”字段。还要注意,我的类中没有显式的“setter”方法(例如),我不想仅仅为了测试的目的创建任何方法。 既然如此,我如何模拟一个字段的值呢?

  • 我尝试测试一个发送jms消息的类,但无法模拟JmsTemplate JmsProducer.class: JmsProducerTest。类别: 当我运行这个测试用例时,它给了我:java。lang.IllegalArgumentException:对象不是声明类的实例 你对这个问题有什么想法吗?

  • 我想模拟注释来检查根据给定注释返回结果的类的良好行为。 Erg.mockito.exceptions.misusing.WurnTypeOfReturnValue:annotationType()不能返回KClassImpl annotationType()应该返回Class 如果你不确定为什么你会超过错误,请继续阅读。由于语法的性质,上面的问题可能会发生,因为: 此异常可能发生在错误编写的多线程

  • 问题内容: 我有这样的情况 到目前为止我一直在嘲笑 现在我得到一个读者 但是当我执行此行时,我得到null并且无法前进 请告诉我如何嘲笑这个。请注意,我无法更改我的主要代码,因此在我的情况下,Mockito文档中存在的解决方案无效 测试码 问题答案: 要使此工作正常进行,您需要使用Powermockito来拦截构造函数调用(新的InputStreamReader(…),新的BufferedRead

  • 我一直认为Mockito工作某种代理之类的东西。但现在我发现,Mockito允许我做一些像 这不适用于代理。它是如何做到这一点的?这种技术可以用来调用内部AOP方法吗?(请参见Spring AOP不适用于另一个方法中的方法调用)