繁体   English   中英

使用Mockito调用模拟方法时发生NullPointerException

[英]NullPointerException while invoking mocked method using Mockito

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

被测方法

 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方法,这不应该返回一个模拟对象,否则我做错了方法。

您不是在模拟转换器对象。

ITransformer transformer = new SendDocumentsRESTTransformer();

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

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

在调用之前在测试方法中添加此行

docusignRestProvider.sendDocuments( iClientUserDto, iDocumentSet );

new SendDocumentsRESTTransformer()被调用时,这将指示Mockito返回一个模拟对象,从而在sendDocuments方法转换器内部将其设置为模拟对象。

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

您在此处显示的任何需要这么多测试设置的课程都明显违反了“ 单一职责原则”

单元测试仅在用于可测试的小型生产代码单元时才能发挥其优势。 但是您需要10多个模拟,并在4个类中模拟静态方法才能设置测试用例。

这是个人观点,但是基于很多经验:此类测试对您没有帮助。 您花费数小时来编写仅遵循生产代码实现的测试代码。 您不会以这种方式发现错误。

您仅在需要更改生产代码时才发现单元测试中断。 更糟糕的是:即使是最简单的重构也可能会立即破坏此类单元测试。 而且,当模拟静态内容时,即使另一个类中不相关的更改也有可能变成其他地方失败的单元测试。

这种单元测试对您的工作没有帮助; 相反:它们会使您减速。

换句话说:您不应该花时间了解PowerMock为什么会在这里使您失败(因为您在测试用例中做错了什么)。 相反,您应该执行以下两项操作之一:

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

含义:编写单元测试不是为了实现“ 100%覆盖率”或不允许在某些“具有单元测试”电子表格中打勾。

它们被编写来验证您的代码; 帮助您查找和修复错误。 也许我错了; 但是您在此处显示的内容看起来并不属于“有用”类别。

为什么要嘲笑这里使用的所有类? 这是错误的,在Junit中这不是一个好习惯。 仅模拟服务,不要模拟变压器。 让服务返回xml或任何要转换的对象,然后让转换器完成其工作。确保模拟对象实际上已被模拟。 出道代码并检查对象。 如果没有嘲笑对象,则可能会抛出空指针。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM