【问题标题】:Junit testing error, null pointer in mock methodJunit测试错误,模拟方法中的空指针
【发布时间】:2021-11-28 10:29:09
【问题描述】:

我正在尝试测试我的控制器。我的控制器调用一个服务方法,而这个服务只做一个简单的 Web 服务调用。我试图模拟我的服务以对我的控制器进行测试,但在测试执行时,我的服务抛出错误,因为我的服务中的 Client 类为空。

我的控制器:

@ApiOperation(value = "This endpoint sends the customer's registration data and returns information about the properties of the offer.", response = Oferta.class)
    @PostMapping(path="/concurrentoffers/offer")
    public CompletableFuture<ResponseEntity<Oferta>> postOfertaAsync(@Valid @RequestBody OfertaRequest inDTO) 
            throws IOException, SOAPException, CompletionException,  WebServiceBadResponseException{
        
        logger.info("Start REST postOferta");
        
        CompletableFuture<ResponseEntity<Oferta>> result = CompletableFuture.supplyAsync(()-> {
            try {
                Oferta oferta = ofertasService.identificacionOferta(inDTO).get();
                return ResponseEntity.ok(oferta);
            } catch (Exception e) {
                throw  new CompletionException(e);
            }
        });

我的服务不是所有我们不需要所有代码:

package es.****.ofertasconcurrenteswow.services;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import es.******.ofertasconcurrenteswow.data.apis.crm.ClientCrm;
import es.*******.ofertasconcurrenteswow.data.apis.crm.dtos.OfertaCrm;
import es.*******.ofertasconcurrenteswow.data.apis.crm.dtos.OfertaRequestCRM;
import es.********.ofertasconcurrenteswow.data.apis.crm.dtos.PropuestaCompraCrm;
import es.********.ofertasconcurrenteswow.data.apis.crm.dtos.RespuestaPropuestaCrm;
import es.*******.ofertasconcurrenteswow.data.daos.PropuestaCompraRepository;
import es.*******.ofertasconcurrenteswow.data.daos.entities.PropuestaCompraEntity;
import es.**********.ofertasconcurrenteswow.mapper.EntityMapper;
import es.**********.ofertasconcurrenteswow.mapper.OfertasMapper;
import es.************.ofertasconcurrenteswow.rest.dtos.Oferta;
import es.***********.ofertasconcurrenteswow.rest.dtos.OfertaRequest;
import es.*************.ofertasconcurrenteswow.rest.dtos.PropuestaCompra;
import es.***************.ofertasconcurrenteswow.rest.dtos.RespuestaPropuesta;
import es.***************.ofertasconcurrenteswow.services.email.EmailService;
import es.*******************.ofertasconcurrenteswow.services.exceptions.WebServiceBadResponseException;
import lombok.NoArgsConstructor;

@Service @NoArgsConstructor
public class OfertasConcurrentesService {
    
    private ClientCrm clientCrm;
    private EmailService emailService;
    private PropuestaCompraRepository propuestaCompraRepository;

    private OfertasMapper mapper = OfertasMapper.INSTANCE;
    private EntityMapper entityMapper = EntityMapper.INSTANCE;

    private Logger logger = LoggerFactory.getLogger(OfertasConcurrentesService.class);

    public OfertasConcurrentesService(ClientCrm clientCrm, EmailService emailService,
            PropuestaCompraRepository propuestaCompraRepository) {
        super();
        this.clientCrm = clientCrm;
        this.emailService = emailService;
        this.propuestaCompraRepository = propuestaCompraRepository;
    }
    
    
    public CompletableFuture<Oferta> identificacionOferta(OfertaRequest inDTO) {

        logger.info("Start identificacionOferta");
        
        logger.debug("Mapeamos el dto de entrada rest a el dto de entrada del WSCrm");
        OfertaRequestCRM inDTOCrm = mapper.ofertaRequestDtoRestToOfertaRequestDtoCrm(inDTO);

        logger.debug("Preparamos llamda al Cliente WebService");
        CompletableFuture<OfertaCrm> completableFutureCRM = clientCrm.llamadaWebServiceOfertasAsync(inDTOCrm)
                .thenApply(ofertaCrm -> {
                    // TODO: es el campo codigo?
                    if ("2".equals(ofertaCrm.getCodigo())) {
                        throw new CompletionException(new WebServiceBadResponseException(ofertaCrm.getMensaje()));
                    }
                    return ofertaCrm;
                });

我的测试控制器类:

package es.servihabitat.ofertasconcurrenteswow.rest;

import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;

import javax.xml.soap.SOAPException;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.beans.factory.annotation.Autowired;

import es.************.ofertasconcurrenteswow.data.apis.crm.ClientCrm;
import es.***************.ofertasconcurrenteswow.data.apis.crm.ClientCrmDummyImpl;
import es.****************.ofertasconcurrenteswow.rest.dtos.Inmueble;
import es.***************.ofertasconcurrenteswow.rest.dtos.Oferta;
import es.****************.ofertasconcurrenteswow.rest.dtos.OfertaRequest;
import es.**********************.ofertasconcurrenteswow.services.OfertasConcurrentesService;
import es.*******************.ofertasconcurrenteswow.services.exceptions.WebServiceBadResponseException;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class OfertaConcurrenteControllerTest {

    @Mock
    private ClientCrm clientCrm;/* = new ClientCrmDummyImpl();*/
    
    @Mock
    OfertasConcurrentesService ofertasService ;
    @InjectMocks
    OfertaConcurrenteController ofertasController;
    @Autowired
    OfertaRequest ofertaRequest;
    @BeforeAll
     void init() {
        clientCrm=new ClientCrmDummyImpl(); 
        ofertasService = new OfertasConcurrentesService();
        ofertasController = new OfertaConcurrenteController();
        
    }
    @Test
    void testPostOfertaAsync() throws CompletionException, IOException, SOAPException, WebServiceBadResponseException {
        List<Inmueble> listaInmuebles = new ArrayList<Inmueble>();
        listaInmuebles.add(new Inmueble("a","b","c","s","r","t","u"));
        Oferta oferta = new Oferta((long)266500000,LocalDateTime.of(2017, 2, 13, 15, 56),listaInmuebles);
        CompletableFuture<Oferta> futuro = new CompletableFuture<Oferta>();
        futuro.complete(oferta);
        
        ofertaRequest = new OfertaRequest("00457","087945","5642564z","4564","mail@mail.mail");
        when(ofertasService.identificacionOferta(ofertaRequest)).thenReturn(futuro);
        
        //when(ofertasService.identificacionOferta(any(OfertaRequest.class))).thenReturn();
        
        assert ofertasController.postOfertaAsync(ofertaRequest) !=null ;
    }

    @Test
    void testPropuestaCompra() {
        fail("Not yet implemented");
    }

}

还有例外:

java.lang.NullPointerException: Cannot invoke "es.********.ofertasconcurrenteswow.data.apis.crm.ClientCrm.llamadaWebServiceOfertasAsync(es.****.ofertasconcurrenteswow.data.apis.crm.dtos.OfertaRequestCRM)" because "this.clientCrm" is null

【问题讨论】:

  • 你能用 '@BeforeEach' 替换 '@BeforeAll' 吗? @AlejandroMartin
  • 是的,现在我删除了我的服务构造函数,但现在我的“ofertasService”为空,我无法在没有构造函数的测试类中实例化我的 ofertasService?

标签: spring-boot testing junit nullpointerexception mockito


【解决方案1】:

当您使用 JUnit 5 并模拟一些类时,您需要告诉 Spring 您正在使用 mockito 及其注释,例如 @Mock。您有 3 种选择。

1 - 定义测试类时使用@ExtendWith(MockitoExtension.class)

@ExtendWith(MockitoExtension.class)
class OfertaConcurrenteControllerTest {
  @Mock private ClientCrm clientCrm;
···

我更喜欢这个,因为@ExtendWith 与其他扩展兼容。

2 - 使用 MockitoAnnotations.initMocks(this); 为您的测试类启动 mockito

class OfertaConcurrenteControllerTest {
  @Mock private ClientCrm clientCrm;
  @BeforeEach
  void setUp() {
    MockitoAnnotations.initMocks(this);
  }
...

这仍然是声明性的,因为您使用了 @Mock 但您错过了 junit5 框架验证。

3 - 自己创建模拟对象Mockito.mock(ClientCrm.class)

class OfertaConcurrenteControllerTest {
  private ClientCrm clientCrm;
  @BeforeEach
  void setUp() {
    Mockito.mock(ClientCrm.class)
  }
...

这更冗长,但您可以更好地控制您的模拟对象正在做什么。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-27
    • 1970-01-01
    • 2021-03-06
    • 2021-10-13
    • 1970-01-01
    相关资源
    最近更新 更多