2017-04-12 83 views
0

我越來越NPE嘲笑一個嘲弄的方法。我的理解是,只要我們使用模擬對象調用方法,模擬就會處理所有其他事情。NullPointerException在使用Mockito調用模擬方法時

被測

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並調用了它的轉換請求方法,不應該返回給我一個模擬對象,或者我以錯誤的方式進行操作。

+1

你能否提供堆棧跟蹤? –

+0

昨天你問同樣的問題時,你讀過我最近的評論嗎?它解釋了你在這裏做錯了什麼。 –

+0

@DavidWallace可能不是......而只是爲了記錄;請在這裏看看我的答案;並隨時提供一些反饋。正如我假設我正在解決他的問題背後的問題。 – GhostCat

回答

1

您不是在嘲笑變壓器對象。

ITransformer transformer = new SendDocumentsRESTTransformer(); 

此行創建實際對象而不是模擬對象。當新的SendDocumentsRESTTransformer()被調用時,你需要指示mockito注入一個模擬對象。使用PowerMockito來做到這一點。

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

調用

docusignRestProvider.sendDocuments(iClientUserDto, iDocumentSet); 

這將指示到的Mockito返回時new SendDocumentsRESTTransformer()在裏面你sendDocuments方法變壓器被設置爲模擬對象因此被稱爲模擬對象之前添加在測試方法這一行。

+0

您是否使用Mockito API,因爲我沒有看到when()和withNoArguments()方法? – Mike

+0

您正在使用PowerMockito。請編輯你的答案。 – Mike

+0

Mockito沒有Mocking構造函數調用的這個特性。使用PowerMockito。 PowerMockito.whenNew(SendDocumentsRESTTransformer.class).withNoArguments() –

1

在這裏給你一個完整的非答案:我認爲你會走錯錯誤的兔子洞。

任何需要進行如此多測試設置的課程,正如您在此處顯示的那樣明顯違反了Single Responsibility Principle

單元測試只有在用於生產代碼的小型可測試單元時才能展現其優點。但是你需要10+個嘲諷,並且嘲諷4個類別的靜態方法,以便設置您的測試用例。

這是個人觀點,但基於很多經驗:這些測試對你沒有幫助。您花費小時編寫測試代碼,只需執行您的生產代碼即可。你沒有找到這樣的錯誤。

只有當您必須更改生產代碼時,纔會發現單元測試中斷。更糟糕的是:即使是最簡單的重構也可能立即破壞這種單元測試。而當嘲弄靜態的東西時,即使是另一個類別的無關變化,也有可能變成其他地方失敗的單元測試。

這樣的單元測試對你的工作沒有幫助;相反:他們放慢你的速度。換句話說:你不應該花時間理解PowerMock爲什麼會在這裏失敗(因爲你在測試用例中做了錯誤)。相反,你應該做兩件事之一:

  • 如果可能,重新設計您的生產代碼。考察SOLID OO設計;並開始修復迄今爲止創建的混亂!瞭解如何編寫testable代碼。
  • 如果這是不可能的,那麼請告訴告訴你寫這種單元測試的人。事先做一些研究;創建統計信息,例如:您在這些測試中發現了多少個錯誤(可能爲0)。然後:說服你的同事真正的問題是什麼;而且編寫這樣的單元測試(很可能)浪費了每個人的時間和精力。

含義:未寫入單元測試來實現「100%覆蓋率」或允許在某些「有單元測試」電子表格中打上覆選標記。

它們是爲了驗證你的代碼而寫的;幫助您找到並修復錯誤。也許我錯了;但是你在這裏展示的內容看起來不像「有用」類別中的任何內容。

+0

當你的老闆出現並告訴你學習Mockito或PowerMock並開始爲這些服務編寫測試用例時,你會打破任何類型的規則,無論是OO還是任何其他原則。你可能有能力說出所有這些,但不是我。所以,讓我學習,讓我解決我的問題。 – Mike

+0

我認爲你錯過了我的觀點:最有可能的是,從商業的角度來看,這種單元測試是一個**糟糕的決定。收集參數;與同齡人保持一致;並將這些意見提供給您的上級。當你出現「我們在這裏浪費錢」時,商界人士通常會很快理解它。當然,當你生活在一個不可能的環境中時,那很難。但請記住:這裏的答案不僅僅是爲OP編寫的。但對於任何來自並且有類似問題的人。並記錄下來:我們的團隊以前寫過這樣的單元測試。他們只... – GhostCat

+0

沒有花費時間(==錢!)。投資從來沒有回報;只是一連串的「破碎的測試」一次又一次。換句話說:這不僅關乎商業價值。這也關乎你,開發者不會發瘋。只需退後一秒。你學習編寫這些測試的所有技能。然後,在3個月內,可怕的事情破裂了。你的經理會轉向**你**並問你:「但你**寫了那些單元測試?你的工作爲什麼不能阻止這個失敗?」你打算告訴他什麼? 「對不起老闆,但是我花在這個上的時間浪費了!」 – GhostCat

0

你爲什麼嘲笑這裏使用的所有類?這是錯誤的,在Junit中這不是一個好習慣。單獨模擬服務,不要模擬變壓器。讓服務返回xml或任何對象進行轉換,並讓轉換器完成它的工作。確保模擬對象實際上被嘲笑。登場代碼並檢查對象。我的對象沒有被嘲笑,那麼它可能會拋出一個空指針。

+0

這已經解決了。而且,我正在使用PowerMock在遇到新關鍵字時返回一個模擬對象。爲什麼我嘲笑這麼多的對象是因爲這個服務很複雜,它也是一個遺留代碼,而且還有很多事情要做。 – Mike