JUnit: тестирование вспомогательного класса с использованием только статических методов - PullRequest
32 голосов
/ 14 марта 2012

Я тестирую вспомогательный класс с использованием только статических методов с JUnit4 и Cobertura. Методы тестирования были легкой задачей и уже сделаны.

Тем не менее, cobertura показывает, что класс не покрыт тестами полностью, так как он нигде не создан.

Я не хочу создавать экземпляр этого класса (это вспомогательный класс), поэтому первое решение состоит в том, чтобы скрыть конструктор (который обычно является хорошим подходом для вспомогательного класса).

Тогда cobertura жалуется, что пустой приватный конструктор не покрыт тестами.

Есть ли какое-либо решение для достижения 100% покрытия кода в такой ситуации?

Покрытие кода требуется от руководства высшего уровня (в данном случае), поэтому для меня получение 100% для этого конкретного класса весьма полезно.

Ответы [ 4 ]

31 голосов
/ 14 марта 2012

Существует несколько решений:

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

  2. Создайте фиктивный статический экземпляр (вы можете вызвать приватный конструктор здесь).Ужасно, но вы можете дать полю имя, сообщающее о ваших намерениях (JUST_TO_SILENCE_COBERTURA - хорошее имя).

  3. Вы можете позволить своему тесту расширить вспомогательный класс,Это по сути вызывает конструктор по умолчанию, но ваш вспомогательный класс больше не может быть final.

Я предлагаю последний подход, особенно потому, что класс больше не может быть final.Если потребитель вашего кода хочет добавить другой вспомогательный метод, он может теперь расширить существующий класс и получить один дескриптор, чтобы получить доступ ко всем вспомогательным методам.Это создает связь вспомогательных методов, которая сообщает намерение (они принадлежат друг другу) - что невозможно, если вспомогательный класс равен final

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

29 голосов
/ 14 марта 2012

Если вам абсолютно необходимо достичь 100% покрытия кода - достоинства этого можно обсудить в другом месте :) - вы можете добиться этого, используя отражение в своих тестах. По привычке, когда я реализую класс статических утилит, я добавляю приватный конструктор, чтобы гарантировать, что экземпляры класса не могут быть созданы. Например:

/** 
 * Constructs a new MyUtilities.
 * @throws InstantiationException
 */
private MyUtilities() throws InstantiationException
{
    throw new InstantiationException("Instances of this type are forbidden.");
}

Тогда ваш тест может выглядеть примерно так:

@Test
public void Test_Constructor_Throws_Exception() throws IllegalAccessException, InstantiationException {
    final Class<?> cls = MyUtilties.class;
    final Constructor<?> c = cls.getDeclaredConstructors()[0];
    c.setAccessible(true);

    Throwable targetException = null;
    try {
        c.newInstance((Object[])null);
    } catch (InvocationTargetException ite) {
        targetException = ite.getTargetException();
    }

    assertNotNull(targetException);
    assertEquals(targetException.getClass(), InstantiationException.class);
}

По сути, здесь вы получаете класс по имени, находите конструкторы для этого типа класса, устанавливаете его в public (вызов setAccessible), вызываете конструктор без аргументов и затем гарантируете, что выбрасывается целевое исключение InstantiationException.

В любом случае, как вы сказали, требование 100% покрытия кода здесь является болезненным, но, похоже, это не в ваших руках, поэтому вы мало что можете с этим поделать. Я на самом деле использовал подходы, подобные вышеупомянутым, в своем собственном коде, и я нашел это полезным, но не с точки зрения тестирования. Скорее, это просто помогло мне узнать немного больше об отражении, чем я знал раньше :)

7 голосов
/ 14 марта 2012

Получение 100% покрытия во всех случаях это хорошо, но в некоторых случаях это невозможно.Конечно, если у вас есть класс, который никогда не создается, Cobertura получит это как неполное тестовое покрытие, потому что эти строки кода на самом деле в классе, но они не проверены.Я никогда не буду вызывать приватный конструктор (я предполагаю, что вы скрыли конструктор, сделав его приватным), поэтому я бы не стал беспокоиться.Тест должен состоять в том, чтобы получить то, что вы ожидаете, и хотя я согласен, что 100% покрытие хорошее, в некоторых случаях (например, это) это бесполезно.Покрытие также.

2 голосов
/ 14 марта 2012

Нет.

Если вы не вызовете закрытый конструктор явно (это будет плохой код), вы не сможете охватить эти строки.

...