2017-01-11 10 views
0

Mockitoを使ってJunitテストを書いたとき、次の問題に直面しました。私のテストは実際のオブジェクトのメソッドを呼び出す代わりにオブジェクトをモックし、NullPointerExceptionを受け取ります。私のコードは以下の通りです:Mockオブジェクトを呼び出す代わりに、実際のオブジェクトを呼び出すメソッド

public class JSFUtilsTest { 

    public JSFUtilsTest() { } 

    JSFUtils jsfUtils = mock(JSFUtils.class); 
    FacesContext facesContext = ContextMocker.mockFacesContext();  
    ExternalContext extContext = mock(ExternalContext.class);  
    Application app = mock(Application.class);  
    ExpressionFactory exFactory = mock(ExpressionFactory.class);  
    ELContext elContext = mock(ELContext.class);  
    ValueExpression valExp = mock(ValueExpression.class); 

    @Test 
    public void testResolveExpression() {   
     when(jsfUtils.resolveExpression("expression")).thenAnswer(new Answer<Object>(){ 
       public Object answer(InvocationOnMock invocation){                     
        when(facesContext.getApplication()).thenReturn(app); 
        when(app.getExpressionFactory()).thenReturn(exFactory); 
        when(facesContext.getELContext()).thenReturn(elContext); 
        when(exFactory.createValueExpression(elContext, "expression", Object.class)).thenReturn(valExp); 
        when(valExp.getValue(elContext)).thenReturn(anyObject()); 
        return valExp.getValue(elContext);                  
       } 
      }); 

     jsfUtils.resolveExpression(anyString()); 

     verify(jsfUtils).resolveExpression(anyString());   
     assertNotNull(jsfUtils.resolveExpression(anyString()));   
    } 

} 

MockでresolveExpression()を呼び出す代わりに、私はJSFUtilsオブジェクトを呼び出しています。 JSFUtils.javaとJSFUtilsTest.javaは異なるパッケージにあります。誰か助けてくれますか?前もって感謝します!

+0

。通常、 'when'と' anyString() 'を使ってモックを設定するかもしれませんが、実際の文字列でメソッドを呼び出すことになります。あなたはそれを逆にしているようです。また、あなたの 'Answer'メソッドが' 'いつ' 'セットアップ' 'を一括して行うのかも分かりません。私はあなたがこのすべてを働かせる方法を理解していません。 – khelwood

+0

テストしようとしているメソッドを疑似しても、実際にテストしているわけではありません。 – khelwood

+0

ご意見ありがとうございます。今私はanyString()を使用して、メソッド呼び出しでwhenとreal文字列を使用します。しかし、私はまだNullPointerExceptionで私の問題がある – Slava

答えて

0

これは単なる例であり、実際のテストではモック上でメソッドを直接呼び出すのではなく、依存関係をOUTに注入するとします。

jsfUtils.resolveExpression("expression")に電話をしているときにあなたの模擬馬が応答すると予想しています。実際にあなたはそれを呼んでいません。私はjsfUtils.resolveExpression(anyString())に変更することをお勧めし、あなたはそれがいくつかの特定の文字列で呼び出される必要がある場合、あなたはそれを確認するブロックを確認することができます。verify(jsfUtils).resolveExpression("expression");

jsfUtils.resolveExpression(anyString());を呼び出すと、正しいアプローチではありません。メソッドanyString()は、実際の呼び出しではなくスタブ用に設計されています。

+0

ありがとう!私の例で依存関係を注入する方法を教えてください。 – Slava

+0

例えば、あなたの 'JsfUtils'クラスのコンストラクタは' JsfUtils(FacesContext facesContext、ExternalContext extContext *など)* 'のように見えます。もちろん、クラスに7つの依存関係があるのは良くないので、分割する方法について考えることができますが、これは別のトピックです。たぶん、この依存関係はまったく必要ありません。 –

+0

'jsfUtils.resolveExpression'の結果を計算するためだけにすべてのモックを使用していることがわかります。それはモックがやるべきことではありません。 –

0

MockでresolveExpression()を呼び出す代わりに、私はJSFUtilsオブジェクトを呼び出しています。

次にモックを作成しませんが、スパイ:

//JSFUtils jsfUtils = mock(JSFUtils.class); 
JSFUtils jsfUtils = spy(new JSFUtils(/* mocks of dependencies if needed */)); 

しかし、あなたの分離を強制するために、テスト中のあなたのクラスの他のいくつかのメソッドの戻り値をモックとしたい場合は、これはのみ必要です単位。

私の見ている限り、これはあなたの例では当てはまりません。だから書く:

//JSFUtils jsfUtils = mock(JSFUtils.class); 
JSFUtils jsfUtils = new JSFUtils(/* mocks of dependencies if needed */); 
@Test 
public void testResolveExpression() {   
    when(jsfUtils.resolveExpression("expression")).thenAnswer(new Answer<Object>(){ 
      public Object answer(InvocationOnMock invocation){                     
       when(facesContext.getApplication()).thenReturn(app); 
       when(app.getExpressionFactory()).thenReturn(exFactory); 
       when(facesContext.getELContext()).thenReturn(elContext); 
       when(exFactory.createValueExpression(elContext, "expression", Object.class)).thenReturn(valExp); 
       when(valExp.getValue(elContext)).thenReturn(anyObject()); 
       return valExp.getValue(elContext);                  
      } 
     });    
    jsfUtils.resolveExpression(anyString()); 
    verify(jsfUtils).resolveExpression(anyString());   
    assertNotNull(jsfUtils.resolveExpression(anyString())); 

は、これは何の意味がありません: あなたがテスト中のあなたのクラスのメソッドをモック(カット)し、その非常に同じメソッドを呼び出します。このようにして、カットの動作を検証するのではなく、モックフレームワークの動作を検証します。

また、同じテスト方法でメソッドを2回呼び出します。あなたはそれを避けるべきです。

あなたはこれまで、あなたのテストを変更する必要があります。これは、ことは非常に混乱に見える

@Test 
public void testResolveExpression() { 
    // arrange (test case specific setup of mocks and DTOs) 
    when(facesContext.getApplication()).thenReturn(app); 
    when(app.getExpressionFactory()).thenReturn(exFactory); 
    when(facesContext.getELContext()).thenReturn(elContext); 
    when(exFactory.createValueExpression(elContext, "expression", Object.class)).thenReturn(valExp); 
    when(valExp.getValue(elContext)).thenReturn(anyObject()); 

    // act (call real method on real object) 
    Object result = jsfUtils.resolveExpression("a valid input"); 

    // assert 
    assertNotNull(result); 
} 
+0

あなたの答えをありがとう。しかし、私は偽のFacesContextが必要なので、JSFUtilsオブジェクトを使用することはできません。 JSFUtilsをモックの代わりに使用するとNullPointerExceptionが発生する – Slava

+0

'getFacesContext()'は静的メソッドであり、* PowerMock(-ito)*を使用してモックする必要があります。しかし、私はもう別の質問を思いつきました.JSFUtilはoracleによって提供されるクラスです。なぜあなたはそれをテストしたいのですか? –

+0

これは単体テストのための私の最初の仕事であり、私はあまりにも疎遠だと思う:) – Slava

関連する問題