2014-11-23 3 views
0

У меня есть метод действия контроллера, который независимо от того, что происходит, всегда возвращает значение null, потому что я хочу, чтобы он перезагрузил одну и ту же страницу. (JSF 2.2).Единица Тестирование метода только с одним результатом

Я успешно использовал mockito, чтобы организовать исполнение вниз по любому пути.

Однако каждый путь в основном вызывает абстрактный метод для добавления сообщения или звонки в стороннюю библиотеку.

Так что я могу утверждать, что он возвращает null, но в этом случае независимо. Я вижу, что эта модель повторяется, поскольку развитие продолжается.

Проблема: я всегда проверяю значение null, несмотря на путь выполнения.

Возможные решения, как я их вижу:

  1. Я очень зеленый, чтобы Mockito, так что может быть что-то еще я могу сделать , чтобы убедиться, что третья сторона и абстрактные методы называются.
  2. Я чувствую, что что-то, что может быть полезно, но хаки - это флаг состояния , чтобы узнать, какое сообщение было просто добавлено в стек. Хакки, потому что его единственным реальным использованием является то, что он будет использоваться для тестирования, как я вижу в настоящее время.

  3. Переоцените мои методы, в этом случае, если я в этой ситуации, потому что мой код неправильный.

  4. У меня нет проблем. Оставьте это как есть, и будьте уверены, что я выполняю каждый путь выполнения и проверяя его результат, даже думал, что он тот же.

Вопрос: Учитывая то, что, как известно, в каком направлении Вы бы первым, чтобы попытаться решить проблему проверки внутренних путей выполнения наружно в модульном тесте? Или есть лучшее решение?

Заранее спасибо.

Обновление с примерами кода, чтобы объяснить проблемы проверки, если это маршрут я должен взять с собой:

try { 
    account.save(); //<-- third party object i don't own, & returns void 
    addInfoMessage("All Updated!"); //<-- abstract method 
    } catch (final ResourceException e) { //<-- third party exception 
    addErrorMessage("Sorry your account could not be updated. ");//<-- abstract method 
    LOG.error("error msg"); 
    } 
    ... 
    return null; 

ответ

0

Похоже, есть, по крайней мере, два исхода, поэтому покрытие их имеет важное значение. Вы можете слегка перепроектировать класс, чтобы упростить тестирование.

public abstract class YourClass { 
    protected abstract void addInfoMessage(String message); 
    protected abstract void addErrorMessage(String message); 

    public void closeTransaction() { 
    try { 
     saveAccountInternal();            /* ! */ 
     addInfoMessage("All Updated!"); 
    } catch (final ResourceException e) { 
     addErrorMessage("Sorry your account could not be updated."); 
    } 
    return null; 
    } 

    /** Package-private. Overridable for testing. */ 
    void saveAccountInternal() throws ResourceException { 
    account.save(); 
    } 
} 

вы разрабатываете класс для подклассов, поэтому проверить его с помощью подкласса:

public class YourClassTest { 
    private static class TestYourClass extends YourClass { 
    boolean saveCalled = false; 
    boolean shouldThrow = false; 
    List<String> infoMessages = new ArrayList<>(); 
    List<String> errorMessages = new ArrayList<>(); 
    protected void addInfoMessage(String message) { infoMessages.add(message); } 
    protected void addErrorMessage(String message) { errorMessages.add(message); } 

    @Override void saveAccountInternal() throws ResourceException { 
     saveCalled = true; 
     if (shouldThrow) throw new ResourceException(); 
    } 
    } 

    @Test public void closeTransactionShouldSave() { 
    TestYourClass testYourClass = new TestYourClass(); 
    assertNull(testYourClass.closeTransaction()); 
    assertTrue(testYourClass.saveCalled); 
    assertEquals(1, testYourClass.infoMessages.size()); 
    assertEquals(0, testYourClass.errorMessages.size()); 
    } 

    @Test public void closeTransactionShouldSave() { 
    TestYourClass testYourClass = new TestYourClass(); 
    testYourClass.shouldThrow = true; 
    assertNull(testYourClass.closeTransaction()); 
    assertTrue(testYourClass.saveCalled); 
    assertEquals(1, testYourClass.infoMessages.size()); 
    assertEquals(0, testYourClass.errorMessages.size()); 
    } 
} 

Обратите внимание, что решение выше не включает Mockito. После того, как вы согласитесь с редизайном тестирования, вы можете использовать Mockito для автоматизации создания подкласса, как в this SO answer.

public class YourClassTest { 
    private YourClass stubYourClass() { 
    YourClass yourClass = Mockito.mock(YourClass.test, Mockito.CALLS_REAL_METHODS); 
    doNothing().when(yourClass).addInfoMessage(anyString()); 
    doNothing().when(yourClass).addErrorMessage(anyString()); 
    doNothing().when(yourClass).saveAccountInternal(); 
    return yourClass; 
    } 

    @Test public void closeTransactionShouldSave() { 
    YourClass yourClass = stubYourClass(); 
    assertNull(yourClass.closeTransaction()); 
    verify(yourClass).saveAccountInternal(); 
    verify(yourClass).addInfoMessage(anyString()); 
    verify(yourClass, never()).addErrorMessage(anyString()); 
    } 

    @Test public void closeTransactionShouldSave() { 
    YourClass yourClass = stubYourClass(); 
    doThrow(new ResourceException()).when(yourClass).saveAccountInternal(); 
    assertNull(yourClass.closeTransaction()); 
    verify(yourClass).saveAccountInternal(); 
    verify(yourClass).addErrorMessage(anyString()); 
    verify(yourClass, never()).addInfoMessage(anyString()); 
    } 
} 

Конечно, утверждая, что «никогда» на сообщениях с информацией/сообщениями об ошибках может сделать ваш тест более хрупким, чем вам хотелось бы; это просто, чтобы показать, что тестирование с использованием подкаталога или подкласса, созданного Mockito, может дать вам всю необходимую артикуляцию для такого рода тестов.

+0

Благодарим вас за отзыв, я попытаюсь сделать это локально, попробовать и оценить его. –

0

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

Проверка нового состояния проста. Тестирование побочных эффектов на зависимостях делается с помощью метода verify() Mockito, как объяснено в very first item of the official documentation:

//Let's import Mockito statically so that the code looks clearer 
import static org.mockito.Mockito.*; 

//mock creation 
List mockedList = mock(List.class); 

//using mock object 
mockedList.add("one"); 
mockedList.clear(); 

//verification 
verify(mockedList).add("one"); 
verify(mockedList).clear(); 
+0

Я должен был заявить, что проверял другие тесты, и я знаю об этом. Но в этом случае я не уверен, что это верно, я обновлю свой вопрос на примере. –

Смежные вопросы