Как вы можете тестировать частные методы?

Я работаю над проектом java. Я новичок в модульном тестировании. Каков наилучший способ модульного тестирования частных методов в Java-классах?

161 голос | спросил Vinoth Kumar C M 14 AM00000080000003331 2011, 08:44:33

10 ответов


221

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

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

ответил Adam Lear 14 AM00000090000003531 2011, 09:40:35
108

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

С другой стороны, иногда разложение деталей реализации на отдельные классы приводит к классам со сложными интерфейсами, множеству данных, проходящих между старым и новым классами, или к дизайну, который может выглядеть хорошо с точки зрения ООП, но не соответствует интуиции, исходящей из проблемной области (например, разделение модели ценообразования на две части, чтобы избежать тестирования частных методов, не очень интуитивно понятное и может привести к проблемам позже при сохранении /расширении кода). Вы не хотите иметь «двойные классы», которые всегда меняются вместе.

Когда вы сталкиваетесь с выбором между инкапсуляцией и тестируемостью, я предпочел бы пойти на второе. Более важно иметь правильный код (т. Е. Производить правильный вывод), чем хороший дизайн ООП, который работает неправильно, потому что он не был протестирован адекватно. В Java вы можете просто предоставить доступ к методу «по умолчанию» и поместить модульный тест в один и тот же пакет. Модульные тесты - это просто часть разрабатываемого вами пакета, и это нормально, чтобы иметь зависимость между тестами и тестируемым кодом. Это означает, что при изменении реализации вам может потребоваться изменить свои тесты, но это нормально - для каждого изменения реализации требуется повторная проверка кода, и если тесты необходимо изменить для этого, тогда вы просто выполните он.

В общем, класс может предлагать несколько интерфейсов. Существует интерфейс для пользователей и интерфейс для сопровождающих. Второй способ может предоставить больше, чтобы обеспечить надлежащий контроль кода. Он не должен быть единичным тестом для частного метода - это может быть, например, регистрация. Регистрация также «ломает инкапсуляцию», но мы все еще это делаем, потому что это так полезно.

ответил quant_dev 14 PM000000120000001631 2011, 12:18:16
26

Тестирование частных методов будет зависеть от их сложности; некоторые частные методы на основе отдельных строк на самом деле не гарантируют дополнительных усилий по тестированию (это также можно сказать об общедоступных методах), но некоторые частные методы могут быть столь же сложными, как и общедоступные методы, и их трудно проверить через открытый интерфейс.

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

Если это связано с аннотацией @VisibleForTesting в библиотеке Google Guava, вы явно отмечаете этот закрытый метод пакета как видимый только для тестирования и как таковой, он не должен вызываться никакими другими классами.

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

Частный метод перед тестированием:

  private int add (int a, int b) {
    return a + b;
}
 

Пакет приватного метода готов к тестированию:

  @VisibleForTesting
int add (int a, int b) {
    return a + b;
}
 

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

ответил Richard 27 22012vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2012 14:43:33 +0400 2012, 14:43:33
13

Если вы не можете использовать внешние API или не хотите, вы можете использовать чистый стандартный JDK API для доступа к приватным методам с использованием отражения. Вот пример

  MyObject obj = new MyObject ();
Метод privateMethod = MyObject.class.getDeclaredMethod ("getFoo", null);
privateMethod.setAccessible (истина);
String returnValue = (String) privateMethod.invoke (obj, null);
System.out.println ("returnValue =" + returnValue);
 

Проверьте учебник по Java http://docs.oracle.com/javase/tutorial/reflect/ или API Java http://docs.oracle.com/javase/7 /docs /api /java /lang /reflection /package-summary.html для получения дополнительной информации.

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

ответил Gustavo Coelho 31 Jpm1000000pmFri, 31 Jan 2014 16:10:31 +040014 2014, 16:10:31
9

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

Если вы используете java, вы можете использовать jmockit, который предоставляет Deencapsulation.invoke для вызова любого частного метода тестируемого класса. Он использует отражение, чтобы называть его в конце концов, но обеспечивает хорошую обертку вокруг него. ( https://code.google.com/p/jmockit/)

ответил agrawalankur 5 FebruaryEurope/MoscowbWed, 05 Feb 2014 07:07:16 +0400000000amWed, 05 Feb 2014 07:07:16 +040014 2014, 07:07:16
8

Прежде всего, как предложили другие авторы: подумайте дважды, если вам действительно нужно проверить частный метод. И если да, то ...

В .NET вы можете преобразовать его в метод «Внутренний» и сделать пакет « InternalVisible " в ваш тестовый проект.

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

Спасибо.

ответил Budda 12 PMpThu, 12 Apr 2012 22:19:57 +040019Thursday 2012, 22:19:57
7

Обычно я защищаю такие методы. Предположим, что ваш класс находится в:

  SRC /главная /Java /вы /Class.java
 

Вы можете создать тестовый класс следующим образом:

  SRC /тест /Java /вы /TestClass.java
 

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

Обратите внимание, что это ожидает исходное дерево в стиле maven.

ответил gyorgyabraham 13 FriEurope/Moscow2013-12-13T14:52:19+04:00Europe/Moscow12bEurope/MoscowFri, 13 Dec 2013 14:52:19 +0400 2013, 14:52:19
3

Если вам действительно нужно проверить частный метод, я имею в виду Java, вы можете использовать fest assert и /или fest . Он использует отражение.

Импортируйте библиотеку с maven (данные версии не являются последними, которые я думаю) или импортируют непосредственно в ваш путь к классам:

  & л; зависимость & GT;
     & Lt; идентификатор_группа & GT; org.easytesting & л; /идентификатор_группа & GT;
     & Lt; артефакт & GT; фест-утверждает & л; /артефакт & GT;
     & Lt; & версии GT; 1,4 & л; /& версии GT;
    & Lt; /зависимость & GT;

    & Lt; & зависимость GT;
     & Lt; идентификатор_группа & GT; org.easytesting & л; /идентификатор_группа & GT;
     & Lt; артефакт & GT; фест-отражает & л; /артефакт & GT;
    & Lt; & версии GT; 1,2 & л; /& версии GT;
& Lt; /зависимость & GT;
 

В качестве примера, если у вас есть класс с именем «MyClass» с приватным методом с именем «myPrivateMethod», который принимает параметр String as, обновите его значение до «это классное тестирование!», вы можете выполнить следующий тест junit

  import static org.fest.reflect.core.Reflection.method;
...

MyClass objectToTest;

@До
public void setUp () {
   objectToTest = новый MyClass ();
}

@Контрольная работа
public void testPrivateMethod () {
   //ДАННЫЙ
   Строка myOriginalString = "toto";
   //КОГДА
   метод ( "myPrivateMethod") withParameterTypes (String.class) .в (objectToTest) .invoke (myOriginalString).
   //ТОГДА
   Assert.assertEquals («это классное тестирование!», MyOriginalString);
}
 

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

ответил kij 27 22012vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2012 13:45:22 +0400 2012, 13:45:22
2

То, что я обычно делаю на C #, делает мои методы защищенными, а не частными. Это немного менее частный модификатор доступа, но он скрывает метод от всех классов, которые не наследуются от тестируемого класса.

  открытый класс classUnderTest
{
   //это обычно будет приватным
   protected void methodToTest ()
   {
     //некоторый код здесь
   }
}
 

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

  class TestingClass: classUnderTest
{
   public void methodToTest ()
   {
     //это возвращает метод, который я хотел бы проверить
     return base.methodToTest ();
   }
}
 

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

ответил spaceman 9 Maypm13 2013, 13:16:22
0

Вы можете легко проверить частные методы, если вы поместите свои юнит-тесты во внутренний класс в тестируемый класс. Используя TestNG, ваши модульные тесты должны быть общедоступными статическими внутренними классами, аннотированными с помощью @Test, например:

  @Test
public static class UserEditorTest {
    public void test_private_method () {
       assertEquals (новый UserEditor (). somePrivateMethod (), «success»);
    }
}
 

Поскольку это внутренний класс, можно вызвать частный метод.

Мои тесты выполняются с maven, и он автоматически находит эти тестовые примеры. Если вы просто хотите протестировать один класс, вы можете сделать

  $ mvn test -Dtest = * UserEditorTest
 

Источник: http://www.ninthavenue.com. аи /как к блоку испытаний приват-методы

ответил Roger Keays 11 AMpThu, 11 Apr 2013 00:44:26 +040044Thursday 2013, 00:44:26

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132