Как проверить приватный конструктор в Java-приложении?

java unit-testing junit

26805 просмотра

7 ответа

38096 Репутация автора

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

private Utils() {
}

Теперь ... как это можно проверить, если этого конструктора не видно? Можно ли вообще это проверить?

Автор: JAM Источник Размещён: 29.12.2012 01:20

Ответы (7)


6 плюса

8462 Репутация автора

@Test
public//
void privateConstructorTest() throws Exception {
    final Constructor<?>[] constructors = Utils.class.getDeclaredConstructors();
    // check that all constructors are 'private':
    for (final Constructor<?> constructor : constructors) {
        Assert.assertTrue(Modifier.isPrivate(constructor.getModifiers()));
    }        
    // call the private constructor:
    constructors[0].setAccessible(true);
    constructors[0].newInstance((Object[]) null);
}
Автор: MrSmith42 Размещён: 29.12.2012 01:23

68 плюса

317182 Репутация автора

Решение

Используя рефлексию, вы можете вызвать приватный конструктор:

Constructor<Util> c = Utils.class.getDeclaredConstructor();
c.setAccessible(true);
Utils u = c.newInstance(); // Hello sailor

Тем не менее, вы можете сделать даже это не возможным:

private Utils() {
    throw new UnsupportedOperationException();
}

Вызывая исключение в конструкторе, вы предотвращаете все попытки.


Я бы тоже сделал сам класс final, просто «потому что»:

public final class Utils {
    private Utils() {
        throw new UnsupportedOperationException();
    }
}
Автор: Bohemian Размещён: 29.12.2012 01:25

19 плюса

10840 Репутация автора

Проверьте смысл кода .. всегда :)

Например: если точка приватности конструктора не видна, то вам нужно проверить этот факт и ничего больше.

Используйте API отражения для запроса конструкторов и проверки того, что у них установлен атрибут private.

Я бы сделал что-то вроде этого:

@Test()
public void testPrivateConstructors() {
    final Constructor<?>[] constructors = Utils.class.getDeclaredConstructors();
    for (Constructor<?> constructor : constructors) {
        assertTrue(Modifier.isPrivate(constructor.getModifiers()));
    }
}

Если вы хотите иметь надлежащий тест для построения объекта, вы должны протестировать публичный API, который позволяет вам получить построенный объект. Вот почему указанный API должен существовать: для правильного построения объектов, поэтому вы должны проверить это :).

Автор: Mihai Toader Размещён: 29.12.2012 01:29

4 плюса

81369 Репутация автора

Если у вас есть приватный конструктор, он вызывается из не очень приватного метода вашего кода. Итак, вы тестируете этот метод, и ваш конструктор покрыт. Там нет религиозной добродетели в том, чтобы иметь тест на метод. Вы ищете функцию или, еще лучше, уровень охвата ветвления, и вы можете получить это, просто используя конструктор через путь к коду, который его использует.

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

Автор: bmargulies Размещён: 29.12.2012 01:34

5 плюса

6488 Репутация автора

чтобы убедиться, что никто по ошибке не инициализирует экземпляр этого класса

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

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

  1. генерировать исключение UnsupportedOperationException («не создавать экземпляр этого класса!») из пустого конструктора по умолчанию.
  2. объявляйте класс абстрактным: если он содержит только статические методы, вы можете вызывать статические методы, но не создавать его экземпляры, если только вы не наследуете его.

или примените оба 1 + 2, вы все равно можете создать подкласс и запустить конструктор, если ваш тест использует тот же пакет, что и целевой класс. Это должно быть вполне "доказательством ошибки"; злоумышленники всегда найдут обходной путь :)

Автор: Luigi R. Viggiano Размещён: 29.12.2012 01:46

3 плюса

976 Репутация автора

Если вы добавите исключение в конструктор, например:

private Utils() {
    throw new UnsupportedOperationException();
}

При вызове constructor.newInstance()в тестовом классе InvocationTargetExceptionвместо вас UnsupportedOperationExceptionбудет выброшено, но в брошенном будет содержаться искомое исключение.
Если вы хотите подтвердить выбрасывание вашего исключения, вы можете выбросить цель исключения вызова после того, как исключение вызова было перехвачено.
Например, используя jUnit 4, вы можете сделать это:

@Test(expected = UnsupportedOperationException.class)
public void utilityClassTest() throws NoSuchMethodException, IllegalAccessException, InstantiationException {
    final Constructor<Utils> constructor = Utils.class.getDeclaredConstructor();
    constructor.setAccessible(true);
    try {
        constructor.newInstance();
    } catch (InvocationTargetException e) {
        throw (UnsupportedOperationException) e.getTargetException();
    }
}
Автор: Juan Размещён: 11.08.2015 09:39

-3 плюса

271204 Репутация автора

Не. Конструктор является частным. Это все, что вам нужно. Java обеспечивает его конфиденциальность.

Не проверяйте платформу.

Автор: user207421 Размещён: 11.08.2015 09:44
Вопросы из категории :
32x32