Вызов частного метода через JMockit для проверки результата

Я использую JMockit 1.1, и все, что я хочу сделать, это вызвать частный метод и проверить возвращаемое значение. Однако мне сложно понять, как именно это сделать, из деинкапсуляции JMockit пример.

Метод, который я пытаюсь протестировать, является частным методом в этом классе:

public class StringToTransaction {
   private List<String> parseTransactionString(final String input) {
      // .. processing
      return resultList;
   }
}

И мой тестовый код ниже.

@Test
public void testParsingForCommas() {
   final StringToTransaction tested = new StringToTransaction();
   final List<String> expected = new ArrayList<String>();
   // Add expected strings list here..
   new Expectations() {
      {
         invoke(tested, "parseTransactionString", "blah blah");
         returns(expected);
      }
   };
}

И ошибка, которую я получаю:

java.lang.IllegalStateException: на данном этапе отсутствует вызов фиктивного типа; убедитесь, что такие вызовы появляются только после объявления подходящего фиктивного поля или параметра

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


person Robert Mark Bram    schedule 24.03.2013    source источник


Ответы (6)


Я думаю, вы слишком усложняете это. Вам вообще не следует использовать блок Expectations. Все, что вам нужно сделать, это примерно так:

@Test
public void testParsingForCommas() {
   StringToTransaction tested = new StringToTransaction();
   List<String> expected = new ArrayList<String>();
   // Add expected strings list here..

   List<String> actual = Deencapsulation.invoke(tested, "parseTransactionString", "blah blah");
   assertEquals(expected, actual);
}

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

person Jeff Olson    schedule 25.03.2013
comment
Привет, @JeffOlson - в каком классе находится метод invoke ()? В ожидании invoke () - это метод защищенного экземпляра. Или, может быть, просто используйте java.lang.reflect.Method.invoke () и вообще игнорируйте JMockit .. - person Robert Mark Bram; 25.03.2013
comment
Наконец-то я понял ... это Deencapsulation.invoke, спасибо @JeffOlson и спасибо Роджерио из groups.google.com/d/msg/jmockit-users/oEgjW0DfmgU/3pEE1mjt1ncJ. - person Robert Mark Bram; 25.03.2013
comment
Да, это правильно. Извините за непонятность, но вы использовали invoke() непосредственно в своем первоначальном примере (предположительно, через статический импорт), поэтому я решил оставить его как есть. Я обновлю свой ответ, чтобы он был более понятным для всех, кто может прочитать это в будущем. - person Jeff Olson; 25.03.2013
comment
Я написал это здесь: robertmarkbramprogrammer.blogspot.com. au / 2013/03 / - person Robert Mark Bram; 26.03.2013
comment
@JeffOlson В последнем jmockit они удалили это. Так есть ли альтернатива для достижения такого же поведения? Этот ответ необходимо обновить. - person IfOnly; 30.01.2019
comment
Да, похоже, вы правы. Я предлагаю посмотреть некоторые ответы на stackoverflow.com/questions/880365/. В частности, ReflectionUtils Spring выглядит интересно. - person Jeff Olson; 01.02.2019

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

@Test
public void testParsingForCommas() throws Exception {
   StringToTransaction tested = new StringToTransaction();
   ArrayList<String> expected = new ArrayList<>();
   expected.add("Test");

   Method declaredMethod =
         tested.getClass().getDeclaredMethod("parseTransactionString",
               String.class);
   declaredMethod.setAccessible(true);
   Object actual = declaredMethod.invoke(tested, "blah blah");
   assertEquals(expected, actual);
}

Здесь важен вызов setAccessible(true), иначе invoke взорвется при вызове частного метода.

declaredMethod.setAccessible(true);

Но вы хотите знать, что на самом деле круто? Если вы не позвоните setAccessible(true), он взорвется с java.lang.StackOverflowError! :)

person Robert Mark Bram    schedule 25.03.2013

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

Этот обходной путь также можно рассматривать как окончательное решение.

Пример:
Фактический класс:

class A {

  private int getId(String name){  //private method
      return DAOManager.getDao().getId(name);  //Call to non-private method can be mocked.
  }
}  

Тестовый класс:

public class ATest{

  @Before
  public void setUp(){
    new MockDAOManager();
  }

  //Mock APIs used by the private method `getId`.
  public static class MockDAOManager extends MockUp<MockDAOManager>{
     static mocked_user_id = 101;

     @Mock
     public DAOManager getDao() throws Exception{
          return new DAOManager();
     }

     @Mock
     public Integer getId(String name){
         return mocked_user_id;
     }
  }
}

Примечание.

  • Если у вас нет такой логики (вызовы частного метода на другой не частный метод), вам, возможно, придется реорганизовать свой код, иначе это не сработает.
  • Здесь DAOManager.getDao().getId(name) не является частным API.
  • Возможно, потребуется имитировать все API, используемые этим частным методом.
person Rohit Gaikwad    schedule 25.05.2021

начать с 1.35 (?) jmockit удалил этот вспомогательный метод. по причинам, что это больше не полезно (что я не совсем понимаю)

но да, эта утилита доступна где-то еще

org.springframework.test.util.ReflectionTestUtils
person zinking    schedule 17.10.2018

Как упомянул @Jeff Olson, вы также можете вызывать частные методы bean-компонента, объявив их @Tested.

Вот пример:

// Java

    @Tested
    private YourServiceImplClass serviceImpl;

    @Test
    public void testPrivateMethod() {
   
          List<String> expected = new ArrayList<String>();
          // Add expected strings list here..

          List<String> actual = Deencapsulation.invoke(serviceImpl, "yourPrivateMethod", "arguments");
          assertEquals(expected, actual);
    }
person Abhishek Ransingh    schedule 30.11.2018

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

person Ankur Shanbhag    schedule 24.03.2013
comment
Привет, @Ankur, прошу прощения, но я ищу ответ о том, как правильно использовать JMockit в этой ситуации (или даже могу ли я). Я не собираюсь обсуждать, почему я должен или не должен тестировать частный метод. Я понимаю, что использование утверждений с помощью общедоступных методов - это еще один способ решения этой проблемы, но я не пытаюсь придумать это здесь. - person Robert Mark Bram; 24.03.2013
comment
Взгляните на это: stackoverflow.com/questions/5729973/ - person Ankur Shanbhag; 24.03.2013
comment
Я могу быть немного скучным @Ankur, но я не могу понять, как применить это решение к моей проблеме. :) Помещение блока Ожидания перед инициализацией проверенного приводит к ошибке компиляции: Проверено не может быть преобразовано в переменную. - person Robert Mark Bram; 24.03.2013
comment
Искал какое-то решение в сети. Нашел одну хорошую ссылку. Пожалуйста, пройдите через это. rockycode.com/blog/easymock-cause-effect-exception-mapping - person Ankur Shanbhag; 24.03.2013
comment
Это использование EasyMock, а не JMockit @Ankur. Образцы их использования выглядят совершенно иначе. - person Robert Mark Bram; 24.03.2013
comment
Иногда я считаю, что имеет смысл протестировать частный метод вместо того, чтобы полагаться на тестовое покрытие через общедоступные методы. - person Jeff Olson; 25.03.2013