如何使用mockito模拟自动装配字段

vij*_*rth 7 java unit-testing mockito

在这里,我尝试模拟Service 类TestServiceImpl的自动装配字段ServiceHelper,我无法通过ServiceHelper类的模拟对象调用方法。

这是我的班级文件:

@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private TestDAO testDAO;
    @Autowired
    private ServiceHelper serviceHelper;

    @Override
    public ResultsModel getResults(Map<String, Object> map) throws WebServiceException_Exception  {     
        return serviceHelper.getResults(map);
    }
Run Code Online (Sandbox Code Playgroud)

二等:

@Repository
public class ServiceHelper {

    private static Logger logger = Logger.getLogger(ServiceHelper.class.getName());

    @Autowired
    ResponseHeader responseHeader;

    public void setResponseHeader(ResponseHeader responseHeader) {
        this.responseHeader = responseHeader;
    }

    public ResultsModel getResults(Map<String, Object> map) throws WebServiceException_Exception {
        ....
        }
Run Code Online (Sandbox Code Playgroud)

和测试类:

@RunWith(MockitoJUnitRunner.class)
public class MockitoTester {

    @InjectMocks
    private TestServiceImpl serviceImpl = new TestServiceImpl();

    @Mock
    private TestDAO testDAO;

    @Mock
    private ServiceHelper sHelper;

    @Before
    public void initMocks(){
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testResult() throws Exception {
        Map<String, Object> map = new HashMap<>();
        map.put("TestId", "test123");
        map.put("lang", "en");
        map.put("cntry", "USA");
        ResultsModel results = new ResultsModel();

        when(sHelper.getResults(map)).thenReturn(results);
        results = serviceImpl.getResults(map);

        Assert.assertEquals(results.getStatus(), "Success");
    }
Run Code Online (Sandbox Code Playgroud)

在我的测试课中:

results = serviceImpl.getResults(map); 

It goes to TestServiceImpl class to method :

public ResultsModel getResults(Map<String, Object> map) throws webServiceException_Exception  {     
        return serviceHelper.getResults(map);
    } 
Run Code Online (Sandbox Code Playgroud)

但在这一点上:

serviceHelper.getResults(map); 
Run Code Online (Sandbox Code Playgroud)

它不会进入内部serviceHelper.getResults(map)并将所有值返回为 Null。

Please suggest where I need to do changes.
Run Code Online (Sandbox Code Playgroud)

sli*_*lim 8

您在这里有三个选择:

  1. 在测试中进行实际的 Spring 自动装配
  2. 使用可以由您的测试合法执行的注入方法(构造函数参数、公共设置器、公共字段 - 按优先顺序排列)
  3. 使用反射来注入你的模拟

选项 1 是真正的集成测试——您可以使用更多 Spring 注释来注释您的测试类@RunWith(SpringRunner.class)并控制依赖项注入。这是一个太大的主题,无法在 SO 答案中涵盖,但是如果您 Google 搜索“spring 集成测试 mockito”,就会有很多例子。


但对于单元测试,我认为最好不要涉及Spring。一个好的 Spring bean 不需要 Spring 来运行。选项 2 只是说,编写您的类,以便单元测试(以及其他任何内容)可以通过正常的 Java 方式注入依赖项(无论是模拟还是其他任何内容)。

我认为构造函数注入是最干净的:

private final ServiceHelper serviceHelper; // note: not annotated

@Autowired
public TestService(ServiceHelper serviceHelper) {
    this.serviceHelper = serviceHelper;
}
Run Code Online (Sandbox Code Playgroud)

但你也可以用public void setServiceHelper(ServiceHelper helper)- 这不太好,因为该字段不能是final

或者通过创建这个领域public——我想你知道这不好的原因。


如果您确定有一个不是由公共构造函数或设置器设置的私有字段,您可以ReflectionUtils.setField()在测试中使用 Spring 的:

 @Mock
 private ServiceHelper serviceHelper;

 private TestService service;

 @Before
 public void configureService() {
     service = new TestService();
     Field field = ReflectionUtils.findField(TestService.class, "serviceHelper");
     ReflectionUtils.setField(field, service, serviceHelper);
 }
Run Code Online (Sandbox Code Playgroud)

(或者,同样,直接使用JDK的反射类,或者其他地方的反射utils)

这是显式地使用反射来破坏您已编码到类中的访问规则。我强烈推荐选项 2。


Plo*_*log 1

我认为问题可能是您正在对方法进行存根以返回相同的对象,然后将其分配给被测方法的结果。即(results这里的对象):

ResultsModel results = new ResultsModel();

when(sHelper.getResults(map)).thenReturn(results);
results = serviceImpl.getResults(map);
Run Code Online (Sandbox Code Playgroud)

当它尝试在 Mockito 中存根该方法时,这可能会导致某种循环混乱,并且它肯定不会使您的断言通过:

Assert.assertEquals(results.getStatus(), "Success");
Run Code Online (Sandbox Code Playgroud)

因为结果的状态永远不会在任何地方设置。

我认为您需要为存根和被测试方法的返回值创建单独的对象,并确保将存根对象设置为“成功”状态:

ResultsModel results = new ResultsModel();
results.setStatus("Success");
when(sHelper.getResults(map)).thenReturn(results);
ResultsModel returnedResults = serviceImpl.getResults(map);
Assert.assertEquals(returnedResults.getStatus(), "Success");
Run Code Online (Sandbox Code Playgroud)