简体   繁体   English

如何模拟实现类?

[英]How do I mock an implementation class?

I have something like this: 我有这样的事情:

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

I want to test the execute() method in SomeClass using JUnit. 我想使用JUnit在SomeClass测试execute()方法。 Since someMethod(String someArg1, String someArg2) calls a REST API, I want to mock someMethod to return some predefined response. 由于someMethod(String someArg1, String someArg2)调用了REST API,因此我想模拟someMethod以返回一些预定义的响应。 But somehow, the real someMethod gets called instead of returning the predefined response. 但是以某种方式,真正的someMethod被调用而不是返回预定义的响应。 How do I make it work? 我该如何运作?

Here is what I have tried using Mockito and PowerMockito: 这是我尝试使用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);
      }
}

Here is an example of injecting dependencies without a framework: 这是在没有框架的情况下注入依赖项的示例:

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

You don't have to do that. 您不必这样做。

You change your method under test to NOT call new directly. 您将被测方法更改为不直接调用new。

Instead you use dependency injection for example. 相反,您可以使用例如依赖注入。

Yes, this could be done with Powermock, but please believe me: doing so is the wrong approach! 是的,可以使用Powermock来完成,但是请相信我:这样做是错误的方法!

This answer is very similar to answer posted by Andreas, the only difference being you can run this with @RunWith(SpringRunner.class) and it will avoid problems with bean instantiation and extra configuration. 这个答案与Andreas发布的答案非常相似,唯一的区别是您可以使用@RunWith(SpringRunner.class)来运行它,它将避免bean实例化和额外配置的问题。 Avoid Powermocks and use it only when you need to mock static classes. 避免使用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