使用Mockito调用mocked方法时出现NullPointerException

时间:2017-04-12 21:09:24

标签: java junit mockito powermock

我在模拟一个模拟方法时得到NPE。我的理解是只要我们使用模拟对象调用方法,mock就会处理其他所有事情。

待测方法

 public IDocumentSet sendDocuments(IClientUserDto cu, IDocumentSet ds) throws ESignatureProviderException {

    logMethodStartDebug(cu, CLASS_NAME, "sendDocuments(IClientUserDto, IDocumentSet)");

    IDocumentSet set = null;

    List<DocumentContent> documentContent = new ArrayList<DocumentContent>();
    Envelope env = new Envelope();
    MultiPart multiPart = new MultiPart();
    String token = null;
    String envId = null;
    String status = null;

    try {           
        List<IDocumentDto> dtos = loadDocuments(cu, ds);
        List<IDocument> docs = ds.getDocuments();
        dtos = validateDocs(docs, dtos);

        ISendDocumentsTransformerArgs args = new SendDocumentsTransformerArgs(cu);
        args.setDocuments(docs);
        args.setDocumentDtos(dtos);
        args.setCallbackConfiguration(getConfiguration().getCallback());
        args.setModuleConfiguration(getModuleConfiguration());

        ITransformer transformer = new SendDocumentsRESTTransformer();
        ITransformerResult result = transformer.transformRequest(args);

JUnit测试用例

@RunWith( PowerMockRunner.class )
@PrepareForTest( {DtoUtils.class, ESignatureSpringUtil.class, AppContext.class, DocusignRESTUtil.class} )
public class TestDocusignRESTProvider {

private String accountId = "025f1a5d-b796-4ba6-85d2-b2a4a90d109c";
private String address;
private IClientUserDto iClientUserDto;
private IClientUserVendorDto iClientUserVendorDto ;
private ILoggingHandler iloggingHandler;
private ApplicationContext applicationContext;
private DocusignRESTClient docusignRestClient;
private WebTarget webTarget;
private Response response;
private Invocation.Builder builder;     
private IDocumentSet iDocumentSet;
private IDocumentManager iDocumentManager;
private IProviderConfiguration iProviderConfiguration;
private ITransformer iTransformer;
private ITransformerResult iTransformerResult;
private IManager iManager;
private SendDocumentsTransformerArgs args;

@Before
public void setUp() throws Exception {
    iClientUserDto = new ClientUserDto();
    iloggingHandler = mock( ILoggingHandler.class );
    applicationContext = mock( ApplicationContext.class );
    iClientUserVendorDto = mock( IClientUserVendorDto.class );
    docusignRestClient = mock( DocusignRESTClient.class );
    webTarget = mock( WebTarget.class );
    response = mock( Response.class );
    builder = mock( Invocation.Builder.class );
    iDocumentSet = mock( IDocumentSet.class );
    iDocumentManager = mock( IDocumentManager.class );
    iProviderConfiguration = mock( IProviderConfiguration.class );
    iTransformer = mock( ITransformer.class );
    iTransformerResult = mock( ITransformerResult.class );
    iManager = mock( IManager.class );
    args = mock( SendDocumentsTransformerArgs.class );
    PowerMockito.mockStatic( DtoUtils.class );
    PowerMockito.mockStatic( ESignatureSpringUtil.class );
    PowerMockito.mockStatic( AppContext.class );
    PowerMockito.mockStatic( DocusignRESTUtil.class );
}

@Test
public void testSendDocuments() throws Exception {
    AppContext.setApplicationContext( applicationContext );
    IClientUserDto iClientUserDto = mock( IClientUserDto.class );

    DocusignRESTProvider docusignRestProvider = new DocusignRESTProvider();
    docusignRestProvider.setLoggingHandler( iloggingHandler );
    docusignRestProvider.setDocumentManager( iDocumentManager );
    docusignRestProvider.setConfiguration( iProviderConfiguration );
    docusignRestProvider.setManager( iManager );

    Mockito.when( iloggingHandler.isGeneralDebugEnabled() ).thenReturn( Boolean.TRUE );
    Mockito.when( iTransformer.transformRequest( args ) ).thenReturn( iTransformerResult );
    docusignRestProvider.sendDocuments( iClientUserDto, iDocumentSet );
}

因此,当代码到达transformer.transformRequest(args);行时,它会爆炸。我在嘲笑ITransformer并在上面调用transformerRequest方法,不应该给我一个模拟对象,或者我是以错误的方式做这件事。

3 个答案:

答案 0 :(得分:1)

你没有嘲笑变形金刚对象。

ITransformer transformer = new SendDocumentsRESTTransformer();

这一行是创建实际对象而不是模拟对象。在调用新的SendDocumentsRESTTransformer()时,您需要指示mockito注入模拟对象。使用PowerMockito执行此操作。

PowerMockito.whenNew(SendDocumentsRESTTransformer.class).withNoArguments()thenReturn(iTransformer);

在调用

之前在测试方法中添加此行
docusignRestProvider.sendDocuments( iClientUserDto, iDocumentSet );

这将指示Mockito在调用new SendDocumentsRESTTransformer()时返回一个模拟对象,因此在sendDocuments方法变换器中设置为mock对象。

答案 1 :(得分:1)

在这里给你一个完整的答案:我认为你正在走错了兔子洞。

任何需要如此众多测试设置的课程都明显违反了Single Responsibility Principle

单位测试只有在用于小型,可测试的生产代码单元时才能展现其优势。但是你需要10个以上的模拟,并在4个类中模拟静态方法,以便设置你的测试用例。

这是个人观点,但基于大量经验:此类测试对您没有帮助。您花费小时来编写仅遵循生产代码实施的测试代码。你不会这样找到错误。

只有在必须更改生产代码时才会发现单元测试中断。更糟糕的是:即使是最简单的重构也可能会立即破坏这样的单元测试。在嘲笑静态的东西时,即使是另一个类中不相关的变化,也有可能在其他地方变成失败的单元测试。

这种单元测试对你的工作没有帮助;恰恰相反:他们让你失望。

换句话说:你不应该花时间理解为什么PowerMock会让你失败(因为你在测试用例中做错了)。相反,你应该做两件事之一:

  • 如果可能,请重新设计您的生产代码。研究SOLID OO设计;并开始修复到目前为止创建的混乱!了解如何编写testable代码。
  • 如果无法做到,请与告诉您编写此类单元测试的人员交谈。提前做一些研究;创建统计信息,例如:您在这些测试中找到了多少错误(可能是0)。然后:说服你的同行真正的问题是什么;写这样的单元测试(很可能)是浪费每个人的时间和精力。

含义:单元测试不是为了达到“100%覆盖率”而编写的,也不是为了在某些“有单元测试”电子表格中加上勾选标记。

编写它们是为了验证您的代码;帮助您找到并修复错误。也许我错了;但是你在这里展示的东西看起来并不像任何属于“有用”类别的东西。

答案 2 :(得分:0)

你为什么要嘲笑这里使用的所有类?这是错误的,这在Junit中不是一个好习惯。单独模拟服务,不要模拟变压器。让服务返回xml或任何对象进行转换,让变换器完成它的工作。确保模拟对象实际上被模拟了。首次亮相代码并检查对象。我对象没有被嘲笑然后它可能会抛出一个空指针。