2017-01-11 3 views
0

Я столкнулся с следующим выпуском, когда я писал тесты Junit с использованием Mockito. Мой тест вызывает методы для реального объекта вместо mock объекта, и я получаю 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()));   
    } 

} 

Вместо вызова resolveExpression() на Мок, я получил вызов на объект JSFUtils. JSFUtils.java и JSFUtilsTest.java находятся в разных пакетах. Кто-нибудь может мне помочь? Заранее спасибо!

+0

Это выглядит очень смущен, чтобы быть. Как правило, вы можете настроить свои mocks, используя 'when' и' anyString() ', но затем вы будете вызывать методы с фактическими строками. Кажется, ты делаешь это назад. Кроме того, я не уверен, почему ваш метод 'Answer' делает более сложную настройку' when'. Я не понимаю, как вы собираетесь все это работать. – khelwood

+0

Если вы издеваетесь над методом, который вы пытаетесь протестировать, то вы на самом деле его вообще не проверяете. – khelwood

+0

Спасибо за ваш комментарий. Теперь я использую anyString() с if и real string в вызове метода. Но у меня все еще есть проблема с 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

Вместо вызова resolveExpression() в Mock, я получил вызов объекта 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())); 

Это не имеет никакого смысла: Вы высмеивать метод вашего класса при испытании (вырезать), а затем вызвать этот очень тот же метод. Таким образом, вы не проверяете поведение вашего разреза, а поведение фальшивых фреймворков.

Также вы вызываете метод дважды в рамках одного и того же метода тестирования. Вам следует избегать этого.

Вы должны изменить свой тест на это:

@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

Спасибо за ваш ответ. Но я не могу использовать объект JSFUtils, потому что мне нужен mock FacesContext. Когда я использую JSFUtils вместо mock, я получаю NullPointerException – Slava

+0

'getFacesContext()' является статическим методом и должен быть изделен с использованием * PowerMock (-ito) *. Но я только что придумал другой вопрос: JSFUtil - это класс, поставленный оракулом. Почему вы хотите проверить это? –

+0

Это моя первая задача для модульного тестирования, и я думаю, что я слишком увлечен :) – Slava