无法模拟最终的Kotlin类,因为方法“应返回Validator”

时间:2020-05-14 08:11:07

标签: java unit-testing mockito

我正在尝试为我的Javalin.io Web应用程序编写单元测试。 Mockito中有a few references用于模拟Context objects,这是Javalins方式,使用户可以访问传入的Web请求。我正在尝试模拟.header(String)类的Context方法,因为被测单元正在读取“ Authorization”标头并对其执行JWT检查。

我的pom包含Mockito的最新版本,should be able to mock final classes

<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-core</artifactId>
  <version>3.2.0</version>
  <scope>test</scope>
</dependency>

我已通过创建内容为resources/mockito-extensions/org.mockito.plugins.MockMaker的文件mock-maker-inline来启用Mockito文档中所述的嵌入式模拟程序。

现在,我有一个愚蠢的测试,它模拟Context对象,并且每当调用上下文对象的header()方法时都应返回“ hello123”。以下代码是 real 单元测试的一部分,但足以在运行测试时引起异常:

  @Test
  void stupidTest1() {
    Context context = mock(Context.class);

    String test1 = "hello123";
    when(context.header("Authorization")).thenReturn(test1);
  }

并尝试了这个:

  @Test
  void stupidTest1() {
    Context context = mock(Context.class);

    String test1 = "hello123";
    given(context.header("Authorization")).willReturn(test1);
  }

使用mvn test执行此测试失败,但例外:

org.mockito.exceptions.misusing.WrongTypeOfReturnValue: 

String cannot be returned by header()
header() should return Validator
***
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. This exception *might* occur in wrongly written multi-threaded tests.
   Please refer to Mockito FAQ on limitations of concurrency testing.
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies - 
   - with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.

    at my.package.stupidTest1(JavalinTest.java:28)

我在做错什么吗?奇怪的一点是,测试有时有时可以成功运行,但是在大多数情况下会失败,尤其是连续运行mvn test命令几次时。

3 个答案:

答案 0 :(得分:1)

我可以在本地重现该问题。 看来在类加载期间存在问题,并且Mockito每次都找不到正确的method。 您可以按以下方式更改测试,以确保找到正确的标头方法。它在我本地工作。

With Range("A1").Validation

    Debug.Print .Formula1         '>> =LST_VIC

    .Modify Formula1:=Replace(.Formula1, "VIC", "QLD")

    Debug.Print .Formula1         '>> =LST_QLD

End With

答案 1 :(得分:0)

open class Context{

    fun header(name: String) : String {
        var token = "DEFAULT TOKEN"
        if(name == "AUTHORIZATION"){
            token =  "Bearer 01234"
        }
        return token
    }

}

测试类:

open class ContextTest {

    var context: Context = mock()

    @Test
    fun testContextWhenHeaderIsAuth(){
        /* Return what the real method returns.*/
        whenever(context.header("AUTHORIZATION")).thenCallRealMethod()
        assertEquals("Bearer 01234", context.header("AUTHORIZATION"))

        /* Mocking the return value to be something you need*/
        whenever(context.header("AUTHORIZATION")).thenReturn("Bearer XXX")
        assertEquals("Bearer XXX", context.header("AUTHORIZATION"))
    }

}

答案 2 :(得分:0)

我在这里尝试了几个建议,但无法始终如一地让 Mockito 与 io.javalin.http.Context 一起工作。它会工作一段时间然后停止工作。或者它可以在调试器中运行,但在正常执行时不起作用。

@Mobigital 的建议对我有用。

模拟 HttpServletRequest 和 HttpServletResponse。

@Test
public void get_csv() throws SQLException
{
    final HttpServletRequest request= mock(HttpServletRequest.class);
    final HttpServletResponse response = mock(HttpServletResponse.class);
    final Map<Class<?>, ?> map = new LinkedHashMap<>();

    // Mocking the Context was not working correctly.
    // https://stackoverflow.com/questions/61792392/final-kotlin-class-can-not-be-mocked-because-method-should-return-validator
    Context ctx = new Context(request, response, map);
    
    when(request.getAttribute("database")).thenReturn(getConnection());

    when(request.getHeader(Header.ACCEPT)).thenReturn("text/csv"); 
    when(request.getQueryString()).thenReturn("my_param=some_value");

    LocationGroupController controller = new LocationGroupController(new MetricRegistry());
    controller.getAll(ctx);

    verify(response).setStatus(200);
    verify(response).setContentType("text/csv");
}