JUnit - 如何模拟局部变量对象方法调用

问题描述 投票:0回答:1

我的用例的代码如下:

我的班级:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class MyClass {
    public String getString() {
        // object need mocking
        ObjectMapper mapper = new ObjectMapper()
        try {
                          // method need mocking
            return mapper.writeValueAsString(List.of("1", "2"));
        }
        catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
}

测试代码:

@Test
public void test_get_string() throws Exception {
    ObjectMapper mapper = Mockito.mock(ObjectMapper.class);
    Mockito.when(mapper.writeValueAsString(Mockito.anyList()))
          .thenThrow(JsonProcessingException.class);
    
    Assertions.assertThrows(RuntimeException.class, () -> {
        new MyClass().getString();
    });
    // -> failed
    // Expected RuntimeException but nothing was thrown
}

我想模拟

ObjectMapper
并使其在
JsonProcessingException
方法调用上抛出
writeValueAsString
,但测试一直失败,就好像它根本不使用我的模拟映射器一样。但是如果我将映射器设为
MyClass
的属性并模拟它,那么测试就会通过。

public class MyClass {
    // make mapper a property
    private ObjectMapper mapper;
    
    public MyClass(ObjectMapper mapper) {
        this.mapper = mapper;
    }

    public String getString() {
        try {
            return mapper.writeValueAsString(List.of("1", "2"));
        }
        catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
}
@Test
public void test_get_string() throws Exception {
    ObjectMapper mapper = Mockito.mock(ObjectMapper.class);
    Mockito.when(mapper.writeValueAsString(Mockito.anyList()))
          .thenThrow(JsonProcessingException.class);
    
    Assertions.assertThrows(RuntimeException.class, () -> {
        // pass mapper on creating object
        new MyClass(mapper).getString();
    }); // -> success
}

如果我不想让映射器成为我的类的属性,我应该如何正确地模拟它?

java mockito junit5
1个回答
3
投票

您无法使用 Mockito 模拟在方法中声明的局部变量。您可以将

ObjectMapper
设为您班级
MyClass
的属性。但如果您不想这样做,另一个选择是在您的
MyClass
中添加一个受保护的方法,该方法返回
ObjectMapper

的实例
public class MyClass {
    public String getString() {
        // object need mocking
        ObjectMapper mapper = createObjectMapper()
        try {
                          // method need mocking
            return mapper.writeValueAsString(List.of("1", "2"));
        }
        catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
   protected ObjectMapper createObjectMapper() {
       return new ObjectMapper();
   }
}

然后在您的测试用例中,您可以

spy
您的类并存根这个新方法以返回模拟的
ObjectMapper
,如下所示:

@Test
public void test_get_string() throws Exception {
    ObjectMapper mapper = Mockito.mock(ObjectMapper.class);
    Mockito.when(mapper.writeValueAsString(Mockito.anyList()))
          .thenThrow(JsonProcessingException.class);
    MyClass myClass = Mockito.spy(new MyClass ());
    doReturn(mapper).when(myClass).createObjectMapper();
    Assertions.assertThrows(RuntimeException.class, () -> {
        myClass.getString();
    });
}
© www.soinside.com 2019 - 2024. All rights reserved.