繁体   English   中英

如何模拟实现类?

[英]How do I mock an implementation class?

我有这样的事情:

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;
    }
}

我想使用JUnit在SomeClass测试execute()方法。 由于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);
      }
}

这是在没有框架的情况下注入依赖项的示例:

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);
  }
}

您不必这样做。

您将被测方法更改为不直接调用new。

相反,您可以使用例如依赖注入。

是的,可以使用Powermock来完成,但是请相信我:这样做是错误的方法!

这个答案与Andreas发布的答案非常相似,唯一的区别是您可以使用@RunWith(SpringRunner.class)来运行它,它将避免bean实例化和额外配置的问题。 避免使用Powermocks,仅在需要模拟静态类时才使用它。

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

import org.springframework.test.context.junit4.SpringRunner;

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);
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM