2017-02-20 25 views
0

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

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

Main.class

Class Main { 
    public String getUserName(String userId) { 
    User user = null; 
    user = getUser(userId); 
    if(user.getName().equals("Stack")) { 
     throw new CustomException("StackOverflow"); 
    } 

    return user.getName(); 

} 

private User getUser(String userId) { 
    // find the user details in database 
    String name = ""; // Get from db 
    String address = ""; // Get from db 
    return new User(name, address); 
} 
} 

испытаний Класс

@Test (expected = CustomException.class) 
public void getUserName_UserId_ThrowsException() { 
    Main main = new Main(); 
    // I need to access the user object returned by getUser(userId) 
    // and spy it, so that when user.getName() is called it returns Stack 
    main.getUserName("124"); 
} 

ответ

0

Вы можете использовать mockPrivate PowerMock, но я не рекомендую. Если у вас есть такая проблема, это обычно означает, что ваш дизайн плох. Почему бы не защитить метод?

+0

Я бы точно не сказал, что создание защищенного метода улучшает качество кода, а скорее издевается над частью «get from db». – skomp

+0

@Egor Я не уверен, что я полностью следую, но как насмехается частный метод, помогите мне создать шпион на пользовательском объекте? – bharathp

1

Есть только два способа доступа к частному:

  1. с использованием отражения
  2. расширить сферу
  3. может быть, ждет Java 9, чтобы использовать новые механизмы области видимости?

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

Но самое главное, вы НЕ должны испытывать слишком глубоко в тестах whitbox. Это может привести к взрыву тестовой установки. Попытайтесь нарезать свой код на более мелкие куски.

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

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

class Main { 

    public String getUserName(String userId) { 
     String username = getUserNameFromInternal(userId); 
     if (userName.equals("Stack")) { 
      throw new CustomException("StackOverflow"); 
     } 
     return user.getName(); 
    } 

    String getUserNameFromInternal(String userId) { 
     User user = getUser(userId); 
     return user.getName(); 
    } 

    ... 

} 

Тест:

@Test (expected = CustomException.class) 
public void getUserName_UserId_ThrowsException() { 
    Main main = Mockito.mock(new Main()); 
    Mockito.when(main.getUserNameInternal("124")).thenReturn("Stack"); 
    main.getUserName("124"); 
} 
+0

Код в моем посте был всего лишь образцом. Представьте случай, когда getUserName использует объект User несколькими способами. Предположим, мы вызываем около 15 методов объекта User в getUserName. Но я только хочу издеваться над поведением одного из этих вызовов методов. Как я могу это сделать? – bharathp

+1

@bharathp Если ** один ** метод делает еще 15 других вызовов на каком-либо объекте, то опять же это указывает на плохой дизайн, а кто-то не понимает, как OO предназначено для использования ;-) – GhostCat

+0

Если вы вызываете 15 методов в getUserName что не влияет на методологию, чтобы испытать метод. Но как @GhostCat упомянул, что это показатель плохого дизайна, вы должны задать вопрос, нарушаете ли вы принцип единой ответственности. Но нарезка метода на кусочки и сдача его в эксплуатацию остается первым шагом к потенциальным рефакторингам. – oopexpert

1

Ваша проблема, звоните в new в вашем частном методе.

И ответ заключается не в том, чтобы обратиться к PowerMock; или изменить видимость этого метода.

Разумным ответом является «извлечь» эту зависимость от «того, что дает мне объект« Пользователь »в свой класс; и предоставить экземпляр этого класса в ваш «Основной» класс. Потому что тогда вы можете просто издеваться над этим «фабричным» объектом; и пусть он сделает все, что вы хотите.

Смысл: ваш текущий код просто трудно проверить. Вместо того, чтобы обойти проблемы, вызванные этим, вы вкладываете время в изучение того, как писать простой в тестировании код; например, наблюдая за этими videos в качестве отправной точки.

С учетом вашего последнего комментария: когда вы имеете дело с устаревшим кодом, вы действительно смотрите на использование PowerMockito. Ключевая часть для понимания: вы не «макет» этого частного метода; вы скорее посмотрите на насмешливый вызов на new User(); как указано here.

+0

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

+0

Что я имел в виду: если бы вы написали свой собственный код здесь; то вам, возможно, захочется отступить и узнать ... как это сделать «лучше». Но при работе с существующим кодом вы не можете касаться, тогда PowerMock - единственный ответ, который у вас есть. См. Мой обновленный ответ и его четвертый абзац ;-) – GhostCat

+0

Я не думаю, что речь идет о устаревшем коде и «новом» коде. В этом случае вопрос - это тестирование белого ящика или тестирование черного ящика. Возникает вопрос: вы заботитесь о потоке управления или не заботитесь о входных параметрах, которые дают определенные результаты, не зная, КАК. Если вы заботитесь о потоке управления, вы несете осторожность в отношении качества кода. Если вы хотите только убедиться, что методы объекта дают результаты, соответствующие спецификации, нет реального ручка для обеспечения качества кода, поскольку каждый поток управления становится «детальностью реализации». – oopexpert