Как проверить частный конструктор в приложении Java?
Если класс содержит кучу статических методов, чтобы убедиться, что никто по ошибке не инициализирует экземпляр этого класса, я сделал частный конструктор:
private Utils() {
}
Теперь... как это можно проверить, учитывая, что конструктор не может быть замечен? Может ли это быть проверено на всех?
Ответы
Ответ 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 обеспечивает конфиденциальность.
Не тестируйте платформу.