简体   繁体   English

Mockito ArgumentCaptor在verify()上给出NullpointerException

[英]Mockito ArgumentCaptor gives NullpointerException on verify()

I'm currently trying to create tests for our Servlets. 我目前正在尝试为我们的Servlet创建测试。 I've mocked HttpServletRequest , HttpServletResponse and an object serving as a database handler. 我嘲笑了HttpServletRequestHttpServletResponse和一个充当数据库处理程序的对象。 In the test for the doPost method, my wish is to compare the values from the Json object and the ArrayList sent to the database object. doPost方法的测试中,我希望比较Json对象和发送到数据库对象的ArrayList的值。

The servlet: servlet:

public class WidgetStatusServlet extends HttpServlet {

private DBController db = new DBController();

    @Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    response.setContentType("application/json");
    JsonParser parser = new JsonParser();
    JsonElement tradeElement = parser.parse(request.getParameter("widgetdata"));
    JsonArray json = tradeElement.getAsJsonArray();
    Gson gson = new Gson();
    Type listType = new TypeToken<List<WidgetStatus>>() {
    }.getType();
    ArrayList<WidgetStatus> widgets = gson.fromJson(json, listType);

    Iterator<WidgetStatus> iterator = widgets.iterator();
    System.out.println("Widgets");
    while (iterator.hasNext()) {
        WidgetStatus node = (WidgetStatus) iterator.next();
        System.out.println(node);
    }

    db.addWidgetStatus(widgets);

}

The test: 考试:

public class WidgetStatusServletTest {

@Captor
private ArgumentCaptor<ArrayList<WidgetStatus>> captor;

private DBController dbMock = mock(DBController.class);
private HttpServletRequest request = mock(HttpServletRequest.class);
private HttpServletResponse response = mock(HttpServletResponse.class);
Repository repository = mock(Repository.class);`


    @Test
public void doPost_ShouldVerifyWidgetsIsProvided() throws Exception {
    final WidgetStatus widget1 = new WidgetStatus("id1", "div_id1", "5", "5", "1", "2", false);
    final WidgetStatus widget2 = new WidgetStatus("id2", "div_id2", "2", "1", "3", "1", true);

    when(request.getParameter("widgetdata")).thenAnswer(new Answer<String>() {
        @Override
        public String answer(InvocationOnMock invocation) throws Throwable {
            ArrayList<WidgetStatus> array = new ArrayList<WidgetStatus>();
            array.add(widget1);
            array.add(widget2);
            String json = new Gson().toJson(array);
            return json;
        }
    });
    new WidgetStatusServlet().doPost(request, response);
    verify(dbMock).addWidgetStatus(captor.capture());
    assertNotNull(captor.getAllValues());


}

When I'm running the test it gives me NullpointerException at the line 当我运行测试时,它NullpointerException上给了我NullpointerException

        verify(dbMock).addWidgetStatus(captor.capture());

What am I doing wrong? 我究竟做错了什么? I've looked at several examples with the same usage of the ArgumentCaptor . 我看了几个与ArgumentCaptor相同用法的例子。 Perhaps this is just a minor error? 也许这只是一个小错误?

If you use the MockitoJUnitRunner to run your test, then an ArgumentCaptor will be created for you, and there's no need to initialise it explicitly. 如果您使用MockitoJUnitRunner来运行测试,那么将为您创建一个ArgumentCaptor ,并且无需显式初始化它。 If you do that, then you can also use the @Mock annotation to create your mock objects, that is, you don't need the mock static method any more. 如果你这样做,那么你也可以使用@Mock注释创建你的模拟对象,也就是说,你不再需要mock静态方法了。 Your test class would then begin like this. 然后你的测试类就会这样开始。

@RunWith(MockitoJUnitRunner.class)
public class WidgetStatusServletTest {

    @Captor private ArgumentCaptor<ArrayList<WidgetStatus>> captor;
    @Mock private DBController mockController;
    @Mock private HttpServletRequest mockRequest;
    @Mock private HttpServletResponse mockResponse;
    @Mock private Repository mockRepository;

This question addresses the issue of whether to use MockitoJUnitRunner , or an explicit call to MockitoAnnotations.initMocks . 此问题解决了是否使用MockitoJUnitRunner或显式调用MockitoAnnotations.initMocks

Just a side note - your test methods will be much easier to read if you use variable names that clearly indicate that your objects are mocks, like I've done here. 只是一个注意事项 - 如果您使用明确表明您的对象是模拟的变量名称,您的测试方法将更容易阅读,就像我在这里做的那样。 Otherwise, in a long test class with many different variables, it's easy to lose track of which variables reference mocks, and which reference "real" objects. 否则,在具有许多不同变量的长测试类中,很容易忽略哪些变量引用模拟,哪些变量引用“真实”对象。

Fields marked with annotations @Mock and @Captor (and also @Spy and @InjectMocks ) will be initialized automatically by Mockito, but only if you call MockitoAnnotations.initMocks(this) in the test class. 标有注释@Mock@Captor (以及@Spy@InjectMocks )的字段将由Mockito自动初始化,但前提是您在测试类中调用MockitoAnnotations.initMocks(this)

You can do this yourself in setUp (JUnit3) or a @Before method (JUnit4), or annotate your test case with @RunWith(MockitoJUnitRunner.class) to get automatic initialization and valiidation. 您可以在自己做setUp (JUnit3)或@Before方法(JUnit4),或注释你的测试用例@RunWith(MockitoJUnitRunner.class)获得自动初始化和valiidation。

You did not initialize your captor object, therefore you cannot execute its capture() method. 您没有初始化captor对象,因此无法执行其capture()方法。 You must initialize an object before you are calling its methods. 您必须在调用其方法之前初始化对象。

It seems like the ArgumentCaptor is not getting initialized. 似乎ArgumentCaptor没有初始化。

When using mockito annotations, they are initialized by either 使用mockito注释时,它们会被初始化

  • Adding the MockitoAnnotations.initMocks(this); 添加MockitoAnnotations.initMocks(this); line in the setup method 设置方法中的行

      @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); } 
  • Or by adding @RunWith(MockitoJUnitRunner.class) annotation to the TestClass. 或者通过将@RunWith(MockitoJUnitRunner.class)注释添加到TestClass中。

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

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