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

ModelMapper使用JUnit Mockito抛出NPE

颜新
2023-03-14

我正在使用ModelMapper进行NPE

目录服务测试

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class CatalogServiceTest {

    @Rule
    public ExpectedException thrown = ExpectedException.none();
    @InjectMocks private CatalogService service;
    @Mock ModelMapper modelMapper;
    @Mock CatalogMapper catalogMapper;
    @Mock CatalogRepository catalogRepository;


    @Before
    public void setUp() throws Exception {
//        MockitoAnnotations.initMocks(this);
        CatalogEntity catalogEntity = new CatalogEntity();
        catalogEntity.setId("id");
        catalogEntity.setCode("code");
        catalogEntity.setType("type");
        catalogEntity.setValue("value");

//        Optional<CatalogEntity> optionalCatalog = Optional.of(catalogEntity);
        when(catalogRepository.findByCode(any(String.class))).thenReturn(catalogEntity);
    }

    @Test
    public void whenFindByCode() {
        //Act
        CatalogDto myCatalogDto = service.findByCode("code");
        //Assert
        assertTrue(myCatalogDto.getCode().equals("code"));
    }
}

目录服务

@Service
public class CatalogService {

    private static final Logger LOGGER = LoggerFactory.getLogger(CatalogService.class);

    @Autowired
    CatalogRepository catalogRepository;

    @Autowired
    CatalogMapper catalogMapper;

    /**
     * 
     * @param type
     * @return catalog objects which type is type
     */
    public List<CatalogDto> findByType(String type) {
        LOGGER.info("Getting catalogs by type {}", type);
        List<CatalogEntity> catalogsEntityList = catalogRepository.findByType(type);
        List<CatalogDto> catalogDtoList = new ArrayList<>();
        catalogsEntityList.forEach(catalogEntity -> {
            catalogDtoList.add(catalogMapper.convertCatalogEntityToCatalogDto(catalogEntity));
        });
        return catalogDtoList;
    }
    
    /**
     * Find catalog by code.
     * @param code
     * @return catalog
     */
    public CatalogDto findByCode(String code) {
        LOGGER.info("Getting catalogs by code {}", code);
        return catalogMapper.convertCatalogEntityToCatalogDto(catalogRepository.findByCode(code));
    }
}

目录映射器

@Component
public class CatalogMapper {
    @Autowired
    private ModelMapper modelMapper;
    
    /**
     * Converts CatalogEntity object to CatalogDto object
     * @param catalogEntity
     * @return converted CatalogDto object
     */
    public CatalogDto convertCatalogEntityToCatalogDto(CatalogEntity catalogEntity) {
        return modelMapper.map(catalogEntity, CatalogDto.class);
    }
}

目录库

@Repository
public interface CatalogRepository extends MongoRepository<CatalogEntity, String> {

    List<CatalogEntity> findByType(String type);

    CatalogEntity findByCode(String code);
    
}

catalogRepository.findByCode(code)按预期返回CatalogEntity对象,问题出现在执行catalogMapper.convertCatalogEntityToCatalogDto(catalogRepository.findByCode(code));返回null之后。

共有1个答案

傅峻
2023-03-14

catalogMapper是一个没有存根方法的模拟。

有几种方法可以修复您的测试:

选项1:仅测试与CatalogMapper的交互

在该选项中,您将存根调用catalogMapper.convertCatalogEntityToCatalogDto。这是一个精简单元测试,您只测试与协作服务的交互。

正如您所说,您希望测试mapper的实际实现,有两个选项:

选项2:使用SpringBootTest

在这个选项中,您依赖SpringBootTest来设置整个应用程序上下文。

您需要进行以下更改:

  • 使用@Autowired而不是@InjectMock使您的对象接受测试
@SpringBootTest
public class CatalogServiceTest {

    @Rule
    public ExpectedException thrown = ExpectedException.none();
    @Autowired
    private CatalogService service;
    @MockBean
    CatalogRepository catalogRepository;

}

选项3:构建您自己需要的服务

  • 摆脱@SpringBootTest
  • 仅模拟要模拟的对象-存储库
  • 为其他服务创建真实对象
  • 您可能需要将服务中的字段注入更改为构造函数注入,这是一个好主意
@Service
public class CatalogService {

    final CatalogRepository catalogRepository;

    final CatalogMapper catalogMapper;

    @Autowired
    public CatalogService(CatalogRepository catalogRepository, CatalogMapper catalogMapper) {
        this.catalogRepository = catalogRepository;
        this.catalogMapper = catalogMapper;
    }
}

这种方法只创建测试使用的对象,而不是整个应用程序上下文,因此可能会导致选项2所述的更精简的测试。

@RunWith(MockitoJUnitRunner.class)
public class CatalogServiceTest {

    @Rule
    public ExpectedException thrown = ExpectedException.none();

    private CatalogService service;
    @Mock
    CatalogRepository catalogRepository;


    @Before
    public void setUp() throws Exception {
        var modelMapper = new ModelMapper();
        var catalogMapper =new CatalogMapper(modelMapper);
        service = new CatalogService(catalogRepository, catalogMapper);

        CatalogEntity catalogEntity = new CatalogEntity();
        catalogEntity.setId("id");
        catalogEntity.setCode("code");
        when(catalogRepository.findByCode(any(String.class))).thenReturn(catalogEntity);
    }

}
 类似资料:
  • ModelMapper,Java Object Mapping 工具,类似BeanUtils,效率略低于Orika,但是内部策略丰富,配置方式更舒适。

  • 我在严格模式下使用ModelMapper 地图(来源:学生到目的地:学生Dto) 为了在地址为空时转义映射,我设置了以下条件 问题是:即使地址不为null,我也要使街道和城市等于null。如何使用严格的映射来解决这个问题

  • 问题内容: 包含多个有关将检查的异常与混合使用的问题。 虽然一些答案暗示使用其方法会导致难以阅读的用户代码。 我将使用此空间来提供可提高可读性的替代解决方案。 请注意,此问题特定于CompletableFuture。 这使我们能够提供更广泛地不扩展到lambda表达式的解决方案。 问题答案: 给定实用程序类(下面提供),用户可以无缝地抛出检查异常: 由lambda引发的任何异常(是否经过检查)都将

  • 我有一个嵌套for循环的方法,如下所示: 在我想在'get leaves()'方法中引入之前,这一直很正常。现在,版本将不会编译,因为它说我有一个未报告的,必须捕获或声明要抛出该。我认为这是因为在多个线程上运行。IDE建议的try/catch块组合不能解决此问题。 在Interrupt parallel Stream execution中发布的第二个解决方案表明,我可能可以使用解决这个问题,但我无

  • 以下代码运行良好: 但是,当我使用orElseThrow从可选: 两者都抛出了一个RuntimeException,有什么想法为什么带有可选的方法不起作用吗? 更新:我的构建基础设施,我尝试用IntelliJ和Maven编译它:

  • 我使用的是Apache httpclient 4.3.6和httpcore 4.3.3(与opensaml 3.3.0捆绑)。我试图通过HTTPS通过代理获取网页,但每次都会收到SocketTimeoutException。HTTP连接工作正常。具体的超时并不重要;它只是需要更长的时间才能以更高的值失败。 示例代码: 尝试连接到代理时引发异常。堆栈跟踪是 这看起来很像Apache问题HTTPCLI