为Junit mockito测试用例中自动连接的嵌套bean抛出nullpointerexception

mnemlml8  于 2023-11-18  发布在  其他
关注(0)|答案(3)|浏览(143)

我为服务层准备了Junit测试用例,从服务方法逻辑调用了一些其他带有autowired的bean,在单元测试用例中,我使用该bean作为autowired,因为它也应该作为代码覆盖的一部分。

class CustomerServiceTest{

   @Autowired(or InjectMocks)
   private EmployeeService employeeService;

   @Autowired
   private CustomerService customerService;

   @Test
   public void testcustomerIdNotNull() {
       //mocking some repository call
       Customer customer = customerService.getCustomerDetails();
       //all other test case code
   }
}

 //Customer Service code
 @Service
 public class CustomerService{

 @Autowired
 EmployeeService employeeService;

 public Customer getCustomerDetails() {
       //some code
      employeeService.getEmployee();   /// **Here it was throwing nullpointerexception** 
    //some logic and complete code
 }
}

字符串
我试过自动连线与间谍,但没有工作。

46scxncf

46scxncf1#

你的设置很奇怪。你的评论表明你认为@Autowired@InjectMocks是可以互换的。他们绝对不是。
你必须问自己的第一个问题是,你是否想运行一个Sping Boot 测试(加载应用程序上下文),或者你是否想执行一个使用普通Java而不使用Spring的测试。
如果您需要Sping Boot 测试:

@SpringBootTest
class CustomerServiceTest{

  @MockBean // register a mock version of your repository bean
  private YourRepository yourRepository;

  @Autowired
  private CustomerService customerService;

  @Test
  public void testcustomerIdNotNull() {
    // mocking some repository call ...
    Customer customer = customerService.getCustomerDetails();
    // all other test case code
  }
}

字符串
如果你不需要Spring的application context并且想要mock你的依赖:

@ExtendWith(MockitoExtension.class)
class CustomerServiceTest{

  @Mock // creates a mock instance
  private YourRepository yourRepository;

  @InjectMocks // creates a real instance and injects mocks
  private CustomerService customerService;

  @Test
  public void testcustomerIdNotNull() {
    // mocking some repository call ...
    Customer customer = customerService.getCustomerDetails();
    // all other test case code
  }
}


Mockito的@Mock@InjectMocks一起使用,Sping Boot 的@MockBean@Autowired也是如此。您不能将它们混合使用。
IIRC,@InjectMocks应该能够注入字段,但如果它不放弃不鼓励的字段注入方法,并将类迁移到构造函数注入:

@Service
public class CustomerService {

  private final EmployeeService employeeService;

  @Autowired
  public CustomerService(final EmployeeService employeeService) {
    this.employeeService = employeeService;
  }

  public Customer getCustomerDetails() {
    //some code
    employeeService.getEmployee();
    //some logic and complete code
  }
}


这有一个额外的好处,允许将字段标记为final。

dsekswqp

dsekswqp2#

如果测试类使用下面的注解进行注解,它将工作(JUnit 4)

@RunWith(SpringRunner.class)
@SpringBootTest

字符串
在JUnit 5的情况下,只使用@SpringBootTest进行注解就足够了。
如果您使用的是JUnit 5,则不需要添加等效的@ExtendWith(SpringExtension.class)作为@SpringBootTest,并且其他@. Test注解已经使用它进行了注解。
请注意,这将加载整个Spring Application上下文,这更适合于集成测试。
单元测试的Angular 来看,建议将@RunWith(MockitoJUnitRunner.class)@InjectMocks@Mock组合使用(JUnit 4)

@RunWith(MockitoJUnitRunner.class)
class CustomerServiceTest{
   @Mock
   private EmployeeService employeeService;

   @InjectMocks
   private CustomerService customerService;

   @Test
   public void testcustomerIdNotNull() {
       //mocking some repository call
       Customer customer = customerService.getCustomerDetails();
       //all other test case code
   }
}


对于Junit 5,将@RunWith(MockitoJUnitRunner.class)替换为@ExtendWith(MockitoExtension.class)

cgvd09ve

cgvd09ve3#

将字段级注入改为基于构造函数的注入,空指针异常问题得到解决。我使用的是Junit 5。这里没有分享完整的代码,只是分享了问题代码和流程。下面是最终的工作代码,

@ExtendWith(MockitoExtension.class)
class CustomerServiceTest{

    @InjectMocks
    private EmployeeService employeeService;

    private CustomerService customerService;

    @BeforeEach
    void setUp(){
        customerService = new CustomerService(employeeService);
    }

    @Test
    public void testcustomerIdNotNull() {
        //mocking some repository call, not shared all other repo code here
        Customer customer = customerService.getCustomerDetails();
        //all other test case code
    }
}

 //Customer Service code
 @Service
 public class CustomerService{

 private final EmployeeService employeeService;

 @Autowired
 public CustomerService(EmployeeService employeeService) {
     this.employeeService = employeeService;
 }

 public Customer getCustomerDetails() {
       //some code
       employeeService.getEmployee();   /// fixed NPE issue
      //some logic and complete code
 }
}

字符串

相关问题