如何在没有 Mockingn 框架的情况下测试在另一个 class 中调用另一个方法的方法

How to test a method which calls another method in another class without Mockingn frameworks

我一直在尝试测试这个场景,但我找不到测试它的好方法。因此,这个被测试的方法创建了一个特定自定义类型的新对象,它在调试期间调用方法 afterwards.Now 当我的代码到达这一点时它检测到正在创建新对象但是当它进入方法时它爆炸了因为某些字段未初始化。我正在测试的 Class 与我的测试失败的 class 之间没有任何关系。没有任何 Mocking 框架,有没有办法对此进行测试。我也无法更改源代码。如果它是一个错误的代码,我仍然可以测试它。

class DocuSigRESTProvider{
 public IDocumentSet sendDocuments() {
 /// code...
 ITransformer transformer = new SendDocumentsRESTTransformer();
 ITransformerResult result = transformer.transformRequest(args);
 }
}

当代码进入 transformrequest() 时,它会因为某些字段而爆炸。它总是创建一个新的,所以即使在我的测试 class 中我创建了一个 SendDocumentRESTTransformer 实例,它也不会找到要在 运行 时间初始化的特定字段。

JUnit

private SendDocumentsRESTTransformer sendDocumentRESTTransfomer;
private ITransformerResult iTransformerResult;   

sendDocumentRESTTransfomer = mock( SendDocumentsRESTTransformer.class );
iTransformerResult = mock( ITransformerResult.class );

@Test
public void testSendDocuments() throws Exception {
    DocusignRESTProvider docusignRestProvider = new DocusignRESTProvider();
    docusignRestProvider.setLoggingHandler( iloggingHandler );
    docusignRestProvider.setDocumentManager( iDocumentManager );
    docusignRestProvider.setConfiguration( iProviderConfiguration );
    docusignRestProvider.setManager( idocTranManager );
    docusignRestProvider.setEmailProcessor( emailProcessor );

    List<IDocumentDto> iDocumentDtoList = new ArrayList<>();
    iDocumentDtoList.add( iDocumentDto );

    List<IDocument> iDocumentList = new ArrayList<>();
    iDocumentList.add( iDocument );

    when( restProvider.loadDocuments( iClientUserDto, iDocumentSet ) ).thenReturn( iDocumentDtoList );
    when( iDocumentSet.getDocuments() ).thenReturn( iDocumentList );
    when( restProvider.validateDocs( anyListOf( IDocument.class ), anyListOf( IDocumentDto.class ) ) ).thenReturn( iDocumentDtoList );
    PowerMockito.whenNew( SendDocumentsRESTTransformer.class ).withAnyArguments().thenReturn( sendDocumentRESTTransfomer );
    when( sendDocumentRESTTransfomer.transformRequest( any( ITransformerArgs.class ) ) ).thenReturn( iTransformerResult );

    iDocumentSet = docusignRestProvider.sendDocuments( iClientUserDto, iDocumentSet );
    assertNotNull( iDocumentSet );
}

这段代码可以测试吗?

一般来说,代码必须以某种方式编写才能进行单元测试。您不能只是采用任何(任意)代码段并以干净的方式对其进行单元测试。

因此,您应该遵守一些 conventions/follow 一些做法。提供的代码片段并没有真正遵循这些做法,因此您不得不使用 PowerMock,只有在绝对没有其他选择的情况下才应该使用(如果有的话)。我个人尽量避免使用 power mock。

第一个经验法则是使用依赖注入,而不是在您的方法中使用 new 关键字创建对象。

所以让我们稍微更改一下您的代码:

class DocuSigRESTProvider{
  private ITransformer transformer;

  public DocuSigRESTProvider(ITransformer transformer) {
     this.transformer = transformer;
  }

  public IDocumentSet sendDocuments() {
     /// code...
     ITransformerResult result = transformer.transformRequest(args);
  }
}

那么我们究竟收获了什么?很多:DocuSigRESTProviderclass 不处理创建 ITransformer 实现(实际上为什么要打扰它,它应该获得一个接口并针对它工作)。接口实现是从外部 injected(阅读构造函数注入、setter 注入等等,我不会深入研究依赖注入,因为它本身就是一个广泛的话题) .

所以应该检查 "code" 部分中写的内容的测试(毕竟你检查了 sendDocuments 方法)在你到达最后一行之前不应该再创建是一个转换器调用。

现在您确实想要 mock/stub 转换器,但这次(这是一个重大改进!)您应该模拟接口而不是真正的实现。通过这种方法,您可以使用 EasyMock/Mockito - 它们都可以为界面创建模拟,甚至可以根据需要制作您自己的 "fake" 实现。

您可以创建一个 setter 方法来注入您的外部依赖项。 像这样。

class DocuSigRESTProvider{
 private ITransformer transformer = new SendDocumentsRESTTransformer();

 public IDocumentSet sendDocuments() {
   /// code...
   ITransformerResult result = transformer.transformRequest(args);
 }
  //package level method
 void setTransformer(ITransformer transformer) {
    this.transformer = transformer
 }
}

然后您可以从您的测试 class.

中注入一个 stub 对象
@Test
public void myTest() {
  DocuSigRESTProvider docusignRestProvider = new DocuSigRESTProvider();
  docusignRestProvider.setTransformer(new SendDocumentsRESTTransformerStub());

  //...rest of test code.
}

private class SendDocumentsRESTTransformerStub extends SendDocumentsRESTTransformer {
  //... Override methods.
}