Я працюю над проектом java. Я новачок в одиничному тестуванні. Який найкращий спосіб поділити тест приватних методів у класах java?
Я працюю над проектом java. Я новачок в одиничному тестуванні. Який найкращий спосіб поділити тест приватних методів у класах java?
Відповіді:
Зазвичай приватні методи тестування не використовуються безпосередньо. Оскільки вони приватні, розгляньте їх як деталі реалізації. Ніхто ніколи не збирається зателефонувати до когось із них і не очікує, що він буде працювати певним чином.
Натомість слід перевірити свій публічний інтерфейс. Якщо методи, що викликають ваші приватні методи, працюють так, як ви очікували, то ви поступово припускаєте, що ваші приватні методи працюють правильно.
Загалом, я б цього уникав. Якщо ваш приватний метод настільки складний, що він потребує окремої одиничної перевірки, це часто означає, що він заслужив власний клас. Це може спонукати вас писати це способом, який може бути використаний повторно. Потім слід протестувати новий клас та викликати загальнодоступний інтерфейс його у старому класі.
З іншого боку, іноді розподілення деталей про реалізацію в окремі класи призводить до класів зі складними інтерфейсами, великою кількістю даних, що передаються між старим та новим класом, або до дизайну, який може виглядати добре з точки зору OOP, але не відповідати інтуїціям, що надходять із проблемної області (наприклад, розділення моделі ціноутворення на дві частини, щоб уникнути тестування приватних методів не дуже інтуїтивно зрозуміло і може призвести до проблем згодом при підтримці / розширенні коду). Ви не хочете мати "побратими", які завжди змінюються разом.
Якщо ви зіткнулися з вибором між інкапсуляцією та тестабельністю, я б краще пішов на друге. Важливіше мати правильний код (тобто виробляти правильний вихід), ніж приємний дизайн OOP, який не працює належним чином, тому що він не був перевірений належним чином. У Java ви можете просто надати методу "за замовчуванням" доступ і помістити тестовий пристрій в той же пакет. Блокові тести - це просто частина пакету, який ви розробляєте, і нормально мати залежність між тестами та кодом, який тестується. Це означає, що коли ви змінюєте реалізацію, можливо, вам доведеться змінити свої тести, але це нормально - кожна зміна реалізації вимагає повторного тестування коду, і якщо для цього потрібно змінити тести, ви просто зробите це.
Взагалі клас може запропонувати кілька інтерфейсів. Є інтерфейс для користувачів та інтерфейс для обслуговуючого персоналу. Другий може викрити більше, щоб забезпечити адекватну перевірку коду. Це не повинно бути одиничним тестом приватного методу - це може бути, наприклад, ведення журналу. Журнал також "порушує інкапсуляцію", але ми все одно робимо це, оскільки це так корисно.
Тестування приватних методів залежало б від їх складності; деякі приватні приватні методи насправді не гарантують додаткових зусиль для тестування (це також можна сказати про публічні методи), але деякі приватні методи можуть бути настільки ж складними, як і публічні методи, і їх важко перевірити через публічний інтерфейс.
Моя краща методика - зробити приватний пакет методів приватним, що дозволить отримати доступ до тестової одиниці в тому ж пакеті, але він все одно буде інкапсульований з усіх інших кодів. Це дасть перевагу тестуванню логіки приватного методу безпосередньо, замість того, щоб покладатися на тест публічного методу, щоб охопити всі частини (можливо) складної логіки.
Якщо це в поєднанні з анотацією @VisibleForTesting в бібліотеці Google Guava, ви чітко позначаєте цей пакет приватним методом як видимий лише для тестування, і він не повинен викликати жодні інші класи.
Противники цієї методики стверджують, що це призведе до порушення інкапсуляції та відкриття приватних методів кодування в одному пакеті. Хоча я погоджуюся, що це порушує інкапсуляцію і відкриває приватний код для інших класів, я стверджую, що тестування складної логіки важливіше, ніж сувора інкапсуляція, а не використання пакетних приватних методів, чітко позначених як видимих лише для тестування, повинно бути відповідальність розробників. використання та зміна бази коду.
Приватний метод перед тестуванням:
private int add(int a, int b){
return a + b;
}
Приватний метод упаковки готовий до тестування:
@VisibleForTesting
int add(int a, int b){
return a + b;
}
Примітка. Поміщення тестів в один і той же пакет не є еквівалентним розміщенню їх у тій же фізичній папці. Розділення основного коду та тестового коду на окремі фізичні структури папок є загальною практикою, але ця методика працюватиме до тих пір, поки класи будуть визначені в одному пакеті.
Якщо ви не можете використовувати зовнішні API чи не хочете, ви все одно можете використовувати чистий стандартний JDK API для доступу до приватних методів за допомогою відображення. Ось приклад
MyObject obj = new MyObject();
Method privateMethod = MyObject.class.getDeclaredMethod("getFoo", null);
privateMethod.setAccessible(true);
String returnValue = (String) privateMethod.invoke(obj, null);
System.out.println("returnValue = " + returnValue);
Перевірте http://docs.oracle.com/javase/tutorial/reflect/ або Java API http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/package-summary. html для отримання додаткової інформації.
Як @kij цитував у своїй відповіді, бувають випадки, коли просте рішення з використанням рефлексії справді добре перевірити приватний метод.
Блок тестування означає тестування одиниці коду. Це не означає тестування інтерфейсу, оскільки якщо ви тестуєте інтерфейс, це не означає, що ви тестуєте одиницю коду. Це стає свого роду тестуванням чорної скриньки. Крім того, краще знайти проблеми на найменшому рівні одиниці, ніж визначати проблеми на рівні інтерфейсу, а потім намагатися налагоджувати те, на якому фрагменті не працювало. Тому тестовий пристрій слід перевірити незалежно від сфери їх застосування. Далі йде спосіб перевірити приватні методи.
Якщо ви використовуєте Java, ви можете використовувати jmockit, який надає Deencapsulation.invoke, щоб викликати будь-який приватний метод класу, який тестується. Він використовує роздуми, щоб викликати це в кінцевому підсумку, але забезпечує гарну обгортку навколо нього. ( https://code.google.com/p/jmockit/ )
Перш за все, як запропонували інші автори: подумайте, чи справді вам потрібно перевірити приватний метод. І якщо так, ...
У .NET ви можете перетворити його у метод "Внутрішній" та зробити пакет " InternalVisible " для вашого тестового проекту.
На Java ви можете самостійно писати тести в класі, який потрібно перевірити, і ваші методи тестування повинні також мати можливість викликати приватні методи. Я насправді не маю великого досвіду Java, тому, мабуть, це не найкраща практика.
Дякую.
Я зазвичай роблю такі методи захищеними. Скажімо, ваш клас знаходиться в:
src/main/java/you/Class.java
Ви можете створити тестовий клас як:
src/test/java/you/TestClass.java
Тепер у вас є доступ до захищених методів і ви можете їх перевірити (JUnit або TestNG насправді не має значення), але ви зберігаєте ці методи від тих, хто вам не хотів.
Зауважте, що це очікує дерево джерела в стилі Maven.
Якщо вам справді потрібно перевірити приватний метод, я маю на увазі Java, ви можете використовувати fest assert
та / або fest reflect
. Тут використовується рефлексія.
Імпортуйте бібліотеку з maven (наведені версії не є останніми, на мою думку) або імпортуйте їх безпосередньо у ваш клас:
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-reflect</artifactId>
<version>1.2</version>
</dependency>
Наприклад, якщо у вас є клас під назвою "MyClass" з приватним методом під назвою "myPrivateMethod", який приймає для параметра String оновлення свого значення на "це класне тестування!", Ви можете зробити наступний тест на юніт:
import static org.fest.reflect.core.Reflection.method;
...
MyClass objectToTest;
@Before
public void setUp(){
objectToTest = new MyClass();
}
@Test
public void testPrivateMethod(){
// GIVEN
String myOriginalString = "toto";
// WHEN
method("myPrivateMethod").withParameterTypes(String.class).in(objectToTest).invoke(myOriginalString);
// THEN
Assert.assertEquals("this is cool testing !", myOriginalString);
}
Ця бібліотека також дозволяє замінити будь-які властивості біна (незалежно від того, вони є приватними і жодні налаштування не записуються) макетом, і використовувати це з Mockito або будь-яким іншим макетним фреймом дуже здорово. Єдине, що ви повинні знати на даний момент (не знаєте, чи буде це краще в наступних версіях) - це ім'я цільового поля / методу, яким ви хочете маніпулювати, та його підпис.
Що я зазвичай роблю в C #, це зробити мої методи захищеними, а не приватними. Це дещо менш модифікатор приватного доступу, але він приховує метод від усіх класів, які не успадковують від тестуваного класу.
public class classUnderTest
{
//this would normally be private
protected void methodToTest()
{
//some code here
}
}
Будь-який клас, який не успадковує безпосередньо клас classUnderTest, не має уявлення про те, що methodToTest навіть існує. У своєму тестовому коді я можу створити спеціальний клас тестування, який розширює та забезпечує доступ до цього методу ...
class TestingClass : classUnderTest
{
public void methodToTest()
{
//this returns the method i would like to test
return base.methodToTest();
}
}
Цей клас існує лише в моєму проекті тестування. Єдиною метою є надання доступу до цього єдиного методу. Це дозволяє мені отримувати доступ до місць, яких у більшості інших класів немає.
protected
є частиною загальнодоступного API та має ті самі обмеження (їх ніколи не можна змінювати, потрібно документувати, ...). В C # ви можете використовувати internal
разом із InternalsVisibleTo
.
Ви можете легко протестувати приватні методи, якщо помістити свої одиничні тести у внутрішній клас класу, який ви тестуєте. Використовуючи TestNG, ваші одиничні тести повинні бути загальнодоступними статичними внутрішніми класами, в яких позначається @Test, наприклад:
@Test
public static class UserEditorTest {
public void test_private_method() {
assertEquals(new UserEditor().somePrivateMethod(), "success");
}
}
Оскільки це внутрішній клас, приватний метод можна назвати.
Мої тести виконуються з Maven, і вони автоматично знаходять ці тестові випадки. Якщо ви просто хочете перевірити один клас, ви можете це зробити
$ mvn test -Dtest=*UserEditorTest
Джерело: http://www.ninthavenue.com.au/how-to-unit-test-private-methods