微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ModelMapper使用JUnit Mockito抛出NPE

如何解决ModelMapper使用JUnit Mockito抛出NPE

我正在使用modelmapper进行NPE

CatalogServiceTest

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

CatalogService

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

CatalogMapper

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

CatalogRepository

@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));后出现了问题。

我正在使用Intellij,这是恰好在执行catalogMapper.convertCatalogEntityToCatalogDto函数之前的断点。

enter image description here

enter image description here

解决方法

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

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

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

在此选项中,您将呼叫catalogMapper.convertCatalogEntityToCatalogDto存入存根。这是一个瘦单元测试,您仅测试与协作服务的交互。

正如您所说的,您要测试mapper的真实实现,有两种选择:

选项2:使用SpringBootTest

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

您需要进行以下更改:

  • 使用@Autowired而非@InjectMock来使您的对象受测
  • 使用@MockBean而非@Mock进行存储库。 SpringBootTest忽略@Mock
  • 摆脱其他模拟物
  • 在创建整个应用程序上下文时,我将排除此选项,除非您的目标是进行全面集成测试(您从代码中的@SpringBootTest开始)
@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);
    }

}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。