Тестирование частного метода с использованием mockito

public class A {

    public void method(boolean b){
          if (b == true)
               method1();
          else
               method2();
    }

    private void method1() {}
    private void method2() {}
}
public class TestA {

    @Test
    public void testMethod() {
      A a = mock(A.class);
      a.method(true);
      //how to test like    verify(a).method1();
    }
}

Как тестировать закрытый метод вызывается или нет, и как тестировать закрытый метод с помощью mockito

Ответ 1

Вы не можете сделать это с помощью Mockito, но вы можете использовать Powermock для расширения Mockito и макетов частных методов. Powermock поддерживает Mockito. Здесь пример.

Ответ 2

Невозможно через mockito. Из wiki

Почему Mockito не издевается над частными методами?

Во-первых, мы не догматичны насчет насмешливых частных методов. Мы только не заботятся о частных методах, поскольку с точки зрения тестирования частных методов не существует. Вот несколько причин Мокито не издевается над частными методами:

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

Очень легко работать - просто измените видимость метода от частного до защищенного пакета (или защищенного).

Это требует, чтобы я потратил время на его реализацию и поддержание. И это не имеет смысла данная точка № 2 и факт, что она уже реализованы в разных инструментах (powermock).

Наконец... Издевательские частные методы - это намек на то, что есть что-то неправильно с пониманием ОО. В OO вам нужны объекты (или роли) для сотрудничать, а не методы. Забудьте о паскале и процедурный код. Думать в объектах.

Ответ 3

Вот небольшой пример того, как это сделать с помощью powermock.

public class Hello {
    private Hello obj;
    private Integer method1(Long id) {
        return id + 10;
    }
} 

Для проверки method1 используйте код:

Hello testObj = new Hello();
Integer result = Whitebox.invokeMethod(testObj, "method1", new Long(10L));

Чтобы установить закрытый объект obj, используйте это:

Hello testObj = new Hello();
Hello newObject = new Hello();
Whitebox.setInternalState(testObj, "obj", newObject);

Ответ 4

Подумайте об этом с точки зрения поведения, а не с точки зрения того, какие методы существуют. Метод method имеет особое поведение, если b истинно. Он имеет другое поведение, если b является ложным. Это означает, что вы должны написать два разных теста для method; по одному для каждого случая. Поэтому вместо трех методов-ориентированных тестов (один для method, один для method1, один для method2, у вас есть два теста, ориентированные на поведение.

В связи с этим (я недавно предложил это в другом потоке SO и получил в результате четырехбуквенное слово, поэтому не стесняйтесь брать это с солью); Мне полезно выбирать имена тестов, которые отражают поведение, которое я тестирую, а не имя метода. Поэтому не называйте ваши тесты testMethod(), testMethod1(), testMethod2() и так далее. Мне нравятся имена типа calculatedPriceIsBasePricePlusTax() или taxIsExcludedWhenExcludeIsTrue(), которые указывают, какое поведение я тестирую; то в рамках каждого тестового метода проверяйте только указанное поведение. Большинство таких действий будут связаны только с одним вызовом публичного метода, но могут включать в себя множество вызовов для частных методов.

Надеюсь, что это поможет.

Ответ 5

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

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

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

Ответ 6

Хотя Mockito не предоставляет такую возможность, вы можете достичь того же результата, используя Mockito + класс JUnit ReflectionUtils или класс Spring ReflectionTestUtils. Ниже приведен пример, взятый из здесь, объясняющий, как вызывать закрытый метод:

ReflectionTestUtils.invokeMethod(student, "saveOrUpdate", "From Unit test");

Полные примеры с ReflectionTestUtils и Mockito можно найти в книге Mockito for Spring

Ответ 7

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

//Service containing the mock method is injected with mockObjects

@InjectMocks
private ServiceContainingPrivateMethod serviceContainingPrivateMethod;

//Using reflection to change accessibility of the private method

Class<?>[] params = new Class<?>[]{PrivateMethodParameterOne.class, PrivateMethodParameterTwo.class};
    Method m = serviceContainingPrivateMethod .getClass().getDeclaredMethod("privateMethod", params);
    //making private method accessible
    m.setAccessible(true); 
    assertNotNull(m.invoke(serviceContainingPrivateMethod, privateMethodParameterOne, privateMethodParameterTwo).equals(null));

Ответ 8

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

Несколько возможных решений (AFAIK):

  • Издеваются над вашими частными методами, но вы не будете "фактически" тестировать свои методы.

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

    public class A{
    
    SomeClass classObj = null;
    
    public void publicMethod(){
       privateMethod();
    }
    
    private void privateMethod(){
         classObj = new SomeClass();
    }
    
    }
    

    [Здесь вы можете протестировать закрытый метод, проверив изменение состояния класса с нуля до нуля.]

  • Скорректируйте свой код немного (надеюсь, что это не устаревший код). Мой фонд написания метода заключается в том, что всегда нужно возвращать что-то (int/boolean). Возвращаемое значение МОЖЕТ или НЕ МОЖЕТ быть использовано реализацией, но оно будет ПОЛЬЗОВАТЬСЯ тестированием

    код.

    public class A
    { 
        public int method(boolean b)
        {
              int nReturn = 0;
              if (b == true)
                   nReturn = method1();
              else
                   nReturn = method2();
        }
    
        private int method1() {}
    
        private int method2() {}
    
    }
    

Ответ 9

Поместите свой тест в тот же пакет, но в другую исходную папку (src/main/java vs. src/test/java) и сделайте эти методы закрытыми. Имоспособность более важна, чем конфиденциальность.

Ответ 10

На самом деле есть способ протестировать методы от частного члена с помощью Mockito. Допустим, у вас есть такой класс:

public class A {
    private SomeOtherClass someOtherClass;
    A() {
        someOtherClass = new SomeOtherClass();
    }
    public void method(boolean b){
        if (b == true)
            someOtherClass.method1();
        else
            someOtherClass.method2();
    }

}

public class SomeOtherClass {
    public void method1() {}
    public void method2() {}
}

Если вы хотите проверить, a.method вызовет метод из SomeOtherClass, вы можете написать что-то вроде ниже.

@Test
public void testPrivateMemberMethodCalled() {
    A a = new A();
    SomeOtherClass someOtherClass = Mockito.spy(new SomeOtherClass());
    ReflectionTestUtils.setField( a, "someOtherClass", someOtherClass);
    a.method( true );

    Mockito.verify( someOtherClass, Mockito.times( 1 ) ).method1();
}

ReflectionTestUtils.setField(); заглушит приватного участника чем-то, на что вы можете шпионить.