Как мне проверить приватную функцию или класс, который имеет закрытые методы, поля или внутренние классы? - PullRequest
2484 голосов
/ 29 августа 2008

Как мне выполнить модульное тестирование (используя xUnit) класс, который имеет внутренние закрытые методы, поля или вложенные классы? Или функция, которая становится закрытой, имея внутреннюю связь (static в C / C ++) или находится в закрытом ( анонимном ) пространстве имен?

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

Ответы [ 48 ]

6 голосов
/ 29 августа 2008

Для Java я бы использовал отражение , поскольку мне не нравится идея изменения доступа к пакету в объявленном методе только для тестирования. Тем не менее, я обычно просто тестирую открытые методы, которые также должны гарантировать, что закрытые методы работают правильно.

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

Это не правда. Вы, безусловно, можете, как уже упоминалось в ответе Джема Катиккаса .

4 голосов
/ 10 января 2018

В c ++: перед включением заголовка класса с закрытой функцией, которую вы хотите протестировать

Используйте этот код:

#define private public
#define protected public
3 голосов
/ 14 февраля 2009

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

Вызов setAccessible(true) делает это.

Единственное ограничение - ClassLoader может запретить вам делать это.

См. Подрыв защиты доступа Java для модульного тестирования (Росс Бертон), чтобы узнать, как это сделать в Java.

3 голосов
/ 15 ноября 2011

Я не уверен, является ли это хорошей техникой, но я разработал следующий шаблон для юнит-тестирования частных методов:

Я не изменяю видимость метода, который хочу протестировать, и добавляю дополнительный метод. Вместо этого я добавляю дополнительный открытый метод для каждого частного метода, который я хочу протестировать. Я называю этот дополнительный метод Test-Port и обозначаю их префиксом t_. Этот Test-Port метод затем просто обращается к соответствующему приватному методу.

Кроме того, я добавляю логический флаг к методу Test-Port, чтобы решить, предоставить ли мне доступ к приватному методу с помощью метода Test-Port извне. Этот флаг затем устанавливается глобально в статическом классе, где я размещаю, например, другие глобальные настройки для приложения. Так что я могу включать и выключать доступ к закрытым методам в одном месте, например, в соответствующем модульном тесте.

3 голосов
/ 29 октября 2017

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

Я собираюсь сказать что-то, что нужно сказать, но многие могут не захотеть слышать. Те из вас, кто дает ответы, которые направляют автора вопроса на «обходной путь», оказывают огромную медвежью услугу сообществу. Тестирование является основной частью всех инженерных дисциплин, вы не хотели бы покупать автомобиль, который не был должным образом протестирован и проверен осмысленно, так почему кто-то захочет покупать или использовать программное обеспечение, которое тестируется плохо? В любом случае причина, по которой люди делают это, заключается в том, что последствия плохо протестированного программного обеспечения ощущаются далеко не сразу, и мы обычно не связываем их с телесными повреждениями. Это очень опасное восприятие, которое будет трудно изменить, но мы несем ответственность за поставку безопасных продуктов независимо от того, что даже руководство заставляет нас делать это. Подумайте, Equifax взломать ...

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

3 голосов
/ 03 июня 2016

Быстрое добавление к комментарию @Cem Catikka при использовании ExpectedException:

Имейте в виду, что ваше ожидаемое исключение будет заключено в InvocationTargetException, поэтому для того, чтобы получить ваше исключение, вам придется устранить причину полученного InvocationTargetException. Что-то вроде (тестирование приватного метода validateRequest () в BizService):

@Rule
public ExpectedException thrown = ExpectedException.none();

@Autowired(required = true)
private BizService svc;


@Test
public void testValidateRequest() throws Exception {

    thrown.expect(BizException.class);
    thrown.expectMessage(expectMessage);

    BizRequest request = /* Mock it, read from source - file, etc. */;
    validateRequest(request);
}

private void validateRequest(BizRequest request) throws Exception {
    Method method = svc.getClass().getDeclaredMethod("validateRequest", BizRequest.class);
    method.setAccessible(true);
    try {
        method.invoke(svc, request);
    }
    catch (InvocationTargetException e) {
        throw ((BizException)e.getCause());
    }
 }
2 голосов
/ 14 февраля 2009

В C # вы могли бы использовать System.Reflection, хотя в Java я не знаю. Хотя я все равно чувствую желание ответить на этот вопрос, так как, если вы «чувствуете, что вам нужно использовать частные методы модульного тестирования», я предполагаю, что есть что-то еще, что не так ...

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

2 голосов
/ 24 июня 2009

Что если ваши тестовые классы находятся в том же пакете, что и класс, который должен быть протестирован?

Но в другом каталоге, конечно, src & classes для вашего исходного кода, test/src и test/classes для ваших тестовых классов. И пусть classes и test/classes будут в вашем классе.

2 голосов
/ 23 ноября 2017

Лучший и правильный юридический способ тестирования закрытого метода Java из тестовой среды - это @ VisibleForTesting аннотации для метода, поэтому такой же метод будет виден для тестовой среды, как и открытый метод.

1 голос
/ 22 сентября 2018

Если у вас есть случай, когда вам действительно нужно протестировать закрытый метод / класс и т. Д. Напрямую, вы можете использовать рефлексию, как уже упоминалось в других ответах. Однако, если дело доходит до этого, вместо непосредственного обращения к рефлексии, я бы предпочел использовать классы util, предоставляемые вашей средой. Например, для Java у нас есть:

Что касается их использования, вы можете найти множество статей в Интернете. Вот тот, который мне особенно понравился:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...