简单地说,Mockito如何实现其流利的流利语法?

时间:2017-07-11 15:47:24

标签: java mockito fluent

我现在处于一种情况,我需要实现类似于Mockito流利语法的东西:

app.post('/contact', function(req, res, next) {
  const username = res.data.username;
  const password = res.data.password;
  res.send('Login details: ' + username + ' / ' + password);
});

我花了大约10分钟来查看github上的源代码,却没有看到实现引用任意方法的基本模式。不知何故,模拟对象必须记录调用的方法,以及传递给它的参数,在when( mock.arbitraryMethod( arg1, matcher2 ) ).thenReturn( foo ); 随后可以获得的某个缓冲区中(它不能“看到”模拟或方法,这将被热切地评估)预先);当你将匹配器传递给该方法而不是常规参数时,问题就会复杂化。

有人总结一下这个伎俩吗?

2 个答案:

答案 0 :(得分:1)

首先,你的例子是错误的。

它应该是这样的:

when( mock.arbitraryMethod( eq(arg1), matcher2.match() ) ).thenReturn( foo );

现在让我们看看它是如何运作的。

  1. eq(arg1)matcher2.match()被调用。这两种方法的调用都存储在一些静态变量中(如调用历史列表)。
  2. mock.arbitraryMethod(...)被调用。它是mock的方法,因此Mockito拦截它并将其调用存储在历史中。
  3. when(...)被调用。这里所有的魔法都是酿造的。它检查历史记录并将其存储在它返回的对象中(然后清除历史记录)。
  4. thenReturn只需配置模拟行为方式。
  5. 它引导我们使用一些限制Mockito用法的规则,例如:

    1. 你不能在调用中混合值和eq(...)之类的东西,因为它不允许找出参数序列。
    2. 要模拟抛出异常的方法,您需要使用其他语法,如doReturn(x).when(...)
    3. 其他一些东西。

答案 1 :(得分:1)

一些小代码可以帮助说明正在发生的事情,并带来一些令人惊讶的结果。您希望使用Mockito的方式(以及您应该使用Mockito的方式)通常看起来像这样:

    @Test
    public void whenClauseExplanation_v1() {
        MyImpl myMock = mock(MyImpl.class);

        when(myMock.getStringObj()).thenReturn("What In The World?");

        assertThat(myMock.getStringObj()).isEqualToIgnoringCase("WHAT IN THE WORLD?");
    }

但是,你可以拆开它实际调用的方式并看到一些令人惊讶的结果:

    @Test
    public void whenClauseExplanation_v2() {
        // 1. The argument to when() is a method call on the mock object, the method being stubbed.
        // 2. Argument gets evaluated before when() is invoked
        // 3. Eval of method call on mock records the invocation and arguments in ThreadLocal storage
        // 4. "when()" is invoked, pops the most recent recorded invocation
        // 5. ".thenReturn()" stubs the method to return a specific value when a matching invocation is encountered

        // To demonstrate this:

        MyImpl myMock = mock(MyImpl.class);

        myMock.getStringObj(); // primes the pump
        when(null).thenReturn("What In The World?");  // Huh? passing null?

        // The argument itself doesn't really matter!  But ordinary usage ensures the invocation is recorded before "when()" is evaluated.
        assertThat(myMock.getStringObj()).isEqualToIgnoringCase("WHAT IN THE WORLD?");
    }

正如您所看到的,when()的参数甚至不重要,除了为thenReturn()的参数中提供的预期返回类型提供类型安全性