2015-07-23 2 views
4

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

Похоже, что если метод издевательства содержит вызов метода на одном из переданных аргументов, статический метод не издевается (и тестовые разрывы). Удаление внутреннего вызова явно не является вариантом. Есть ли что-то очевидное, что я здесь отсутствует?

Вот сокращенный вариант, который ведет себя так же, как ...

public class SmallCalculator { 

    public static int getLength(String string){ 

     int length = 0; 

     //length = string.length(); // Uncomment this line and the mocking no longer works... 

     return length; 
    } 
} 

А вот тест ...

import static org.junit.Assert.assertEquals; 
import static org.mockito.BDDMockito.given; 
import static org.mockito.Matchers.any; 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.powermock.api.mockito.PowerMockito; 
import org.powermock.core.classloader.annotations.PrepareForTest; 
import org.powermock.modules.junit4.PowerMockRunner; 

import com.solveit.aps.transport.model.impl.SmallCalculator; 

@RunWith(PowerMockRunner.class) 
@PrepareForTest({ SmallCalculator.class}) 
public class SmallTester { 

    @Test 
    public void smallTest(){ 

     PowerMockito.spy(SmallCalculator.class); 
     given(SmallCalculator.getLength(any(String.class))).willReturn(5); 

     assertEquals(5, SmallCalculator.getLength("")); 
    } 
} 

Кажется, есть некоторая путаница в вопросе, так что я имею придумал более «реалистичный» пример. Это добавляет уровень косвенности, так что не кажется, что я тестирую метод издевательства напрямую. Класс SmallCalculator неизменна:

public class BigCalculator { 

    public int getLength(){ 

     int length = SmallCalculator.getLength("random string"); 

     // ... other logic 

     return length; 
    } 

    public static void main(String... args){ 

     new BigCalculator(); 
    } 
} 

И вот новый класс тест ...

import static org.junit.Assert.assertEquals; 
import static org.mockito.BDDMockito.given; 
import static org.mockito.Matchers.any; 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.powermock.api.mockito.PowerMockito; 
import org.powermock.core.classloader.annotations.PrepareForTest; 
import org.powermock.modules.junit4.PowerMockRunner; 

import com.solveit.aps.transport.model.impl.BigCalculator; 
import com.solveit.aps.transport.model.impl.SmallCalculator; 

@RunWith(PowerMockRunner.class) 
@PrepareForTest({ SmallCalculator.class}) 
public class BigTester { 

    @Test 
    public void bigTest(){ 

     PowerMockito.spy(SmallCalculator.class); 
     given(SmallCalculator.getLength(any(String.class))).willReturn(5); 

     BigCalculator bigCalculator = new BigCalculator(); 
     assertEquals(5, bigCalculator.getLength()); 
    } 
} 
+0

И что происходит? –

+0

, если только этот фрагмент кода/теста не является доказательством того, что издевательская структура не позволяет макетировать то, что, как предполагается, издевается над этим, здесь возникает большая путаница. Нужно ** НЕ ** макетировать класс, который проходит под тестом, а скорее она издевается над своими зависимостями, чтобы она могла протестировать поведение класса. – Alp

+0

В этом примере я получаю NPE, когда вызывается string.length(). Это странно, потому что кажется, что аргумент заменяется, но фактический метод не издевается. – maccaroo

ответ

12

Я нашел ответ здесь https://blog.codecentric.de/en/2011/11/testing-and-mocking-of-static-methods-in-java/

Вот окончательный код, который работает. Я тестировал этот подход в исходном коде (а также надуманный пример), и он отлично работает. Образцы ...

import static org.junit.Assert.assertEquals; 
import static org.mockito.Matchers.any; 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.powermock.api.mockito.PowerMockito; 
import org.powermock.core.classloader.annotations.PrepareForTest; 
import org.powermock.modules.junit4.PowerMockRunner; 

@RunWith(PowerMockRunner.class) 
@PrepareForTest({ SmallCalculator.class}) 
public class BigTester { 

    @Test 
    public void bigTest(){ 

     PowerMockito.mockStatic(SmallCalculator.class); 
     PowerMockito.when(SmallCalculator.getLength(any(String.class))).thenReturn(5); 

     BigCalculator bigCalculator = new BigCalculator(); 
     assertEquals(5, bigCalculator.getLength()); 
    } 
} 
+0

'PowerMockito.when' - ключ для меня. – Arpit

1

Использование anyString() вместо any(String.class).

При использовании any(String.class) пропущенный аргумент null как Mockito будет возвращать значение по умолчанию для типа отсчета, которая null. В результате вы получаете исключение.

При использовании anyString() переданный аргумент будет пустой строкой.

Обратите внимание, что это объясняет, почему вы получаете исключение, однако вам необходимо просмотреть способ тестирования вашего метода, как объяснено в других комментариях и ответах.

+0

Дело в том, что внутренняя работа метода издевательства никогда не должна учитываться, поэтому значение параметра строки не должно иметь значения. – maccaroo

1

Прежде всего, удалите эту строку:

given(SmallCalculator.getLength(any(String.class))).willReturn(5);

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

Во-вторых, изменить аннотацию к:

@PrepareForTest({ SmallCalculator.class, String.class}) 

Наконец, добавьте макет для длины(); как это:

given(String.length()).willReturn(5); 

Я думаю, что он будет делать;)

+0

Я не тестирую тот же метод, что и я, насмехаясь. Я обновил этот пример, чтобы проиллюстрировать это лучше. – maccaroo

0

Если вы не хотите, чтобы этот действительный метод вызывался.Вместо

when(myMethodcall()).thenReturn(myResult); 

использования

doReturn(myResult).when(myMethodCall()); 

Он издевается над магией, и это трудно объяснить, почему это на самом деле работает.

Другое дело вы забыли это mockStatic(SmallCalculator.class)

И вам не нужно PowerMockito.spy(SmallCalculator.class);

Смежные вопросы