Подтвердить что ты не робот

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

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

private Utils() {
}

Теперь... как это можно проверить, учитывая, что конструктор не может быть замечен? Может ли это быть проверено на всех?

4b9b3361

Ответ 1

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

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();
    }
}

Ответ 2

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

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

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

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

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

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

Ответ 3

@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);
}

Ответ 4

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

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

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

  • throw UnsupportedOperationException ( "не создавайте экземпляр этого класса!" ) из конструктора пустой по умолчанию.
  • объявить абстрактный класс: если он содержит только статические методы, вы можете вызвать статические методы, но не создавать его, если вы не подклассифицируете его.

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

Ответ 5

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

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

Ответ 6

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

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();
    }
}

Ответ 7

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

Не тестируйте платформу.