简体   繁体   English

Mockito不使用@Spy模拟私人变量

[英]Mockito not mocking private variables using @Spy

I am attempting to mock a private instance variable listOfStrings using Mockito's @Spy annotation. 我正在尝试使用Mockito的@Spy注释模拟私有实例变量listOfStrings

@RunWith(MockitoJUnitRunner.class)
public class MyObjectTest {

  @InjectMocks
  MyObject myObject;
  @Spy
  List<String> listOfStrings;

  @Before
  public void before() {
    myObject = new MyObject();
  }

  @Test
  public void testCallListOfStrings() {
    Mockito.doReturn(new ArrayList().stream()).when(listOfStrings).stream();
    myObject.callListOfStrings();
  }
}

and

public class MyObject {

  private List<String> listOfStrings;

  public void callListOfStrings() {
    listOfStrings.stream().forEach(System.out::println);
  }
}

It does not appear to be mocking the instance variable, throwing a NullPointerException , obviously. 它似乎并没有嘲笑实例变量,显然抛出了NullPointerException

myObject = new MyObject(); - this is the root of the problem. -这是问题的根源。 Mockito instantiates the mock for you, but you're replacing the mock with your own myObject instance, what leads to NPE (obviously, the listOfStrings is null in your newly instantiated object). Mockito为您实例化该模拟,但是您要用自己的myObject实例替换该模拟,这会导致NPE(显然,新实例化的对象中的listOfStrings为null)。

That how it should work: 那应该如何工作:

@RunWith(MockitoJUnitRunner.class)
public class MyObjectTest {

    // Don't do this with List! 
    // Type 'List' is an interface and it cannot be spied on.
    @Spy
    private ArrayList<String> listOfStrings;
    @InjectMocks
    private MyObject myObject;

    @Before
    public void before() {
        listOfStrings.addAll(List.of("test", "test2"));
    }

    @Test
    public void testCallListOfStrings() {
        Mockito.doReturn(new ArrayList().stream()).when(listOfStrings).stream();
        myObject.callListOfStrings();
    }
}

Output: 输出:

test
test2

You forgot to call Mockito.initMocks(this) inside before() . 您忘记了在Mockito.initMocks(this)内部调用Mockito.initMocks(this) before() Also, you don't need to initialize myObject because mockito will initialize it for you. 另外,您不需要初始化myObject因为mockito会为您初始化它。

I would also like to note that your test really isn't doing anything, because you're not asserting or verifying anything, you're just calling the MyObject.call ListOfString() method. 我还要指出的是,您的测试实际上并没有做任何事情,因为您没有断言或验证任何事情,您只是在调用MyObject.call ListOfString()方法。

Did you try With Java Reflection. 您是否尝试过使用Java Reflection。 I think you need to avoid the null pointer exception. 我认为您需要避免空指针异常。

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

import java.lang.reflect.Field;
import java.util.ArrayList;

@RunWith(MockitoJUnitRunner.class)
public class MyObjectTest {

    @InjectMocks
    MyObject myObject;

    @Before
    public void before() {
        myObject = new MyObject();
    }

    @Test
    public void testCallListOfStrings() throws NoSuchFieldException, IllegalAccessException {

        Field list = myObject.getClass().getDeclaredField("listOfStrings");
        list.setAccessible(true); // Suppress Java language access checking
        list.set(myObject,new ArrayList<>());
        myObject.callListOfStrings();
    }
}

You can assign a value for the private variable 您可以为私有变量分配一个值

listOfStrings listOfStrings

That will avoid the null pointer exception. 这样可以避免空指针异常。

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

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