不会被嘲笑的自动装配的豆上的空指针

时间:2018-09-21 20:34:13

标签: java spring-boot mockito

我有一个需要进行单元测试的服务类。该服务具有上载方法,该方法又调用其他服务(自动装配的Bean)来更新数据库。我需要模拟其中的一些服务,并按原样执行。

@Service
public class UploadServiceImpl implements UploadService{
  @Autowired
  private ServiceA serviceA;

  @Autowired
  private ServiceB serviceB;

  public void upload(){
    serviceA.execute();
    serviceB.execute():

    //code...
}

在上面的示例中,我需要模拟ServiceA,但我希望ServiceB按原样运行并执行其功能。 我的Junit测试看起来像这样:

@RunWith(SpringJUnit4ClassRunner.class) 
@SpringBootTest(classes=Swagger2SpringBoot.class) 
public class UploadServiceTest {
  @Mock
  private ServiceA serviceA;

  @InjectMocks
  private UploadServiceImpl uploadService;

  @Before
  public void init() {
    MockitoAnnotations.initMocks(this);
  }

  @Test
  public void testUpload(){
    uploadService.upload();

  }

执行此操作时,我会在serviceB.execute();中的UploadServiceImpl处获得NPE。

可能是什么问题?

注意:我没有指定模拟对象的行为,因为我并不在乎,而且模拟对象的默认行为也不执行任何操作。

谢谢!

5 个答案:

答案 0 :(得分:3)

通常在进行单元测试时,您要模拟 all 类的外部依赖关系。这样,单元测试可以保持独立,并专注于被测类。

尽管如此,如果您想将Spring自动装配与Mockito模拟混合在一起,一个简单的解决方案是同时使用let mobileNumer = starifyNumber(number: "+91987654321") print(mobileNumer) \\+91*******21 @InjectMocks进行注释:

@Autowired

其最终结果是,首先Spring将自动装配bean,然后Mockito将立即使用可用的模拟覆盖模拟的依赖项。

答案 1 :(得分:1)

添加

  @Mock
  private ServiceB serviceB;

像创建服务A一样创建缺少服务的可注入模拟。

答案 2 :(得分:0)

您面临的问题是由于使用了@InjectMocks注释。@InjectMocks标记了应该执行注入的字段。 Mockito将尝试仅通过构造函数注入,setter注入或属性注入按此顺序注入模拟。如果任何给定的注射策略失败,则Mockito将不会报告失败。

所以在您的情况下,当尝试注入模拟时,仅存在一个模拟bean,而另一个 ServiceA 没有注入。要解决此问题:

您可以尝试完全不使用@InjectMocks,而将其余自动装配对象传递给构造函数时,为要模拟的方法传递一个模拟对象。示例:

在这里测试我是否传递了一个模拟对象和一个自动装配对象。

@RunWith(MockitoJUnitRunner.class)
public class SampleTestServiceImplTest {

@Mock
private SampleClient sampleClient;
@Autowired
private BackendService backendService ;

private BackendServiceImpl backendServiceimpl;

@Before
void setUp() {
    backendServiceimpl = new BackendServiceImpl(sampleClient, backendService);
}

另一种实现此目的的方法是将@Autowired注释与@InjectMocks.@Autowired @InjectMocks一起使用,并且将注入模拟类,而Autowired注释会添加其他依赖项,课程可能有。

来自https://medium.com/@vatsalsinghal/autowired-and-injectmocks-in-tandem-a424517fdd29

的答案

答案 3 :(得分:0)

在我的情况下,除了使用@InjectMocks和@Autowired的组合之外,我还必须为测试类中的模拟对象提供设置器(原始示例中UploadServiceImpl中ServiceA的设置器)。否则,将调用ServiceA的真实方法。

答案 4 :(得分:0)

另一种方法是定义自动装配的构造函数,以便您可以正确测试服务。

@Service
public class UploadServiceImpl implements UploadService{

  private ServiceA serviceA;
  private ServiceB serviceB;

  @Autowired
  public UploadServiceImpl(ServiceA serviceA, ServiceB serviceB) {
    this.serviceA = serviceA;
    this.serviceB = serviceB;
  }

  public void upload(){
    serviceA.execute();
    serviceB.execute():

    //code...
}