2017-02-17 9 views
1

У меня есть что-то вроде этого:Как мне высмеять класс реализации?

public interface SomeInterface { 
    public String someMethod(String someArg1, String someArg2); 
} 

public class SomeInterfaceImpl { 

    @Override 
    public String someMethod(String someArg1, String someArg2) { 
     String response; 

     // a REST API call which fetches response (need to mock this) 

     return response; 
    } 
} 

public class SomeClass { 

    public int execute() { 

     int returnValue; 

     // some code 

     SomeInterface someInterface = new SomeInterfaceImpl(); 
     String response = someInterface.someMethod("some1", "some2"); 

     // some code 

     return returnValue; 
    } 
} 

Я хочу, чтобы проверить метод execute() в SomeClass с помощью JUnit. Поскольку someMethod(String someArg1, String someArg2) вызывает REST API, я хочу высмеять someMethod, чтобы вернуть некоторый предопределенный ответ. Но почему-то реальный someMethod вызывается вместо того, чтобы возвращать предопределенный ответ. Как мне заставить работать?

Вот что я попытался с помощью Mockito и PowerMockito:

@RunWith(PowerMockRunner.class) 
@PrepareForTest({ SomeInterface.class, SomeInterfaceImpl.class, SomeClass.class }) 
public class SomeClassTest { 

    @Test 
    public void testExecute() { 
     String predefinedResponse = "Some predefined response"; 
     int expectedReturnValue = 10; 

     SomeInterfaceImpl impl = PowerMockito.mock(SomeInterfaceImpl.class); 
     PowerMockito.whenNew(SomeInterfaceImpl.class).withAnyArguments().thenReturn(impl); 
     PowerMockito.when(impl.someMethod(Mockito.any(), Mockito.any())).thenReturn(predefinedResponse); 

     SomeClass someClass = new SomeClass(); 
     int actualReturnValue = someClass.execute(); 
     assertEquals(expectedReturnValue, actualReturnValue); 
     } 
} 
+0

Связанного? http://stackoverflow.com/questions/25317804/using-powermockito-whennew-is-not-getting-mocked-and-original-method-is-called –

+4

Это * точно *, где вводится инъекция зависимостей. используйте 'new', передайте' SomeInterface' в качестве параметра. – chrylis

+0

@AndyTurner Я попробовал 'SomeInterface interface = PowerMockito.mock (SomeInterface.class)', за которым следует 'PowerMockito.when (interface.someMethod (Mockito.any(), Mockito.any())). ThenReturn (predefinedResponse);' , Это привело к одной и той же проблеме. – user87407

ответ

1

Вы не должны делать это.

Вы меняете свой тестируемый метод, чтобы НЕ позвонить напрямую.

Вместо этого вы используете инъекцию зависимости, например.

Да, это может быть сделано с Powermock, но, пожалуйста, поверьте мне: это неправильный подход!

+0

Означает ли это, что мне нужно добавить поддержку Spring для инъекции зависимостей или, возможно, добавить установщик для 'SomeInterfaceImpl'? Боюсь, мне не разрешили реорганизовать код. Не могли бы вы показать, как это можно сделать с помощью PowerMock? – user87407

+2

Включение зависимостей не означает использование рамки DI: это просто означает, что вы передаете зависимости в экземпляр, как-то - параметры конструктора, сеттеры, рамки DI ... –

+0

Кроме того, 'SomeInterface' имеет несколько реализаций, используемых в разных классах, таких как' SomeClass'. Какой класс использовать, решается во время выполнения на основе некоторого критерия, создается экземпляр с использованием отражения и его метод execute. Таким образом, невозможно будет установить реализацию 'SomeInterface' или передать его в конструкторе. – user87407

3

Вот пример инъекционных зависимостей без рамки:

import org.junit.Before; 
import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.mockito.InjectMocks; 
import org.mockito.Mock; 
import org.mockito.runners.MockitoJUnitRunner; 

import static org.junit.Assert.assertEquals; 
import static org.mockito.Matchers.anyString; 
import static org.mockito.Mockito.when; 

interface SomeInterface { 
    String someMethod(String someArg1, String someArg2); 
} 

class SomeInterfaceImpl implements SomeInterface { 

    @Override 
    public String someMethod(String someArg1, String someArg2) { 
    String response; 

    response = "the answer.";// a REST API call which fetches response (need to mock this) 

    return response; 
    } 
} 

class SomeClass { 
    private final SomeInterface someInterface; 

    SomeClass(final SomeInterface someInterface) { 
    this.someInterface = someInterface; 
    } 

    public SomeClass() { 
    this(new SomeInterfaceImpl()); 
    } 

    public int execute() { 

    int returnValue; 

    // some code 

    String response = someInterface.someMethod("some1", "some2"); 

    returnValue = 42; // some code 

    return returnValue; 
    } 
} 

@RunWith(MockitoJUnitRunner.class) 
class SomeClassTest { 
    private static final String SOME_PREDEFINED_RESPONSE = "Some predefined response"; 
    @Mock 
    private SomeInterface someInterface; 
    @InjectMocks 
    private SomeClass underTest; 

    @Before 
    public void setup() { 
    when(someInterface.someMethod(anyString(), anyString())).thenReturn(SOME_PREDEFINED_RESPONSE); 
    } 

    @Test 
    public void testExecute() { 
    int expectedReturnValue = 42; 
    int actualReturnValue = underTest.execute(); 
    assertEquals(expectedReturnValue, actualReturnValue); 
    } 
} 
+0

Нет, не работает. Та же проблема. – user87407

+0

Если вы покажете мне, что вы пробовали, я буду рад помочь. – Andreas

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