模拟对象的自动装配字段在Mockito中返回null

时间:2019-11-15 12:39:45

标签: java unit-testing mockito junit4

我有一个StudentService班。而且我编写了一个用于StudentService类的单元测试方法的类。我的代码如下:-

@Component
@EnableAutoConfiguration
public class StudentService {

@Autowired
StudentInstitutionMapper studentInstitutionMapper;

public Integer getPresentStudentCount(StudentParams studentParam) {
    // TODO Auto-generated method stub
    StudentInstitutionExample example = new StudentInstitutionExample();
    StudentInstitutionExample.Criteria criteria = example.createCriteria();
    criteria.andActiveYnEqualTo("Y");
    criteria.andDeleteYnEqualTo("N");
    criteria.andIsPresentEqualTo("Y");
    criteria.andInstitutionTestIdEqualTo(studentParam.getInstitutionTestId());
    List<StudentInstitution> studentInstitutionList = studentInstitutionMapper.selectByExample(example);//line 8 in method
    return studentInstitutionList.size();
}


}

在单元测试课中,我编写了以下方法。

    @Test
    public void testStudentService_getPresentStudentCount1()
    {



        StudentService service=new StudentService();
        StudentParams studentParam=mock(StudentParams.class);

        Integer institutionTestId=3539;
        when(studentParam.getInstitutionTestId()).thenReturn(institutionTestId);


        int i=service.getPresentStudentCount(studentParam);
        assertEquals(0,i);

    }

当我执行测试类时,出现错误。这是因为在StudentService类的getPresentStudentCount()方法的第8行中,studentInstitutionMapper字段为null。这仅发生在模拟对象上。如何获得模拟对象的自动装配字段?

4 个答案:

答案 0 :(得分:1)

尝试在测试类中像这样声明对象studentInstitutionMapper

@Mock
StudentInstitutionMapper studentInstitutionMapper;

答案 1 :(得分:1)

您可以使用@Mock注释注入自动装配的类。在许多情况下,您应该使用@InjectMocks批注创建测试类实例,这要归功于您的模拟可以直接注入。

@RunWith(PowerMockRunner.class)
@PrepareForTest({StudentService.class})
public class StudentServiceTest {

@InjectMocks
StudentService service;

@Mock
StudentInstitutionMapper studentInstitutionMapper;

@Test
public void testStudentService_getPresentStudentCount1()
{
    MockitoAnnotations.initMocks(this);

    StudentParams studentParam=mock(StudentParams.class);

    Integer institutionTestId=3539;
    when(studentParam.getInstitutionTestId()).thenReturn(institutionTestId);


    int i=service.getPresentStudentCount(studentParam);
    assertEquals(0,i);


}

这将有助于更好地解释:Difference between @Mock and @InjectMocks

答案 2 :(得分:1)

有一个简单的解决方案,其中不涉及模拟的高级注释:

您可以像这样重构StudentService

public class StudentService {

    private final StudentInstitutionMapper studentInstitutionMapper;

    public StudentService(StudentInstitutionMapper studentInstitutionMapper) {
       this.studentInstitutionMapper = studentInstitutionMapper;
    }
}

此解决方案是我最喜欢的解决方案,因为当我在测试中创建StudentService时,我会确切地看到它需要什么依赖项以及它们的类型。因此,即使不打开StudentService类的源代码,我也可以提供模拟/真实实现。

这种类型的注入的另一个好处(构造函数注入与您在问题中使用的字段注入相反)不会破坏字段的封装。

注意:

  1. 我没有将@Autowired放在构造函数上,因为在最新版本的spring中,只要有一个构造函数(对于单元测试而言,它根本不相关)就不需要了。

  2. 如果您担心构造函数的样板代码,可以使用Lombok并添加注释以为您生成all-args构造函数。结合注释1,可以完全删除构造函数代码

P.S。我不打算在这里开始现场注入与构造函数注入的“圣战”,我只是在说明这种方法,因为没有人在其他答案中提到过它,并且从技术上讲它解决了问题中提出的问题。随时向Google询问有关此主题的信息。

答案 3 :(得分:0)

您需要在单元测试中使用@InjectMocks批注:

@ExtendWith(MockitoExtension.class)
class StudentServiceTest {

    @Mock
    private StudentInstitutionMapper studentInstitutionMapper;

    @InjectMocks
    private StudentService studentService;

    @Test
    public void testStudentService_getPresentStudentCount1() {


        StudentParams studentParam = mock(StudentParams.class);

        Integer institutionTestId = 3539;
        when(studentParam.getInstitutionTestId()).thenReturn(institutionTestId);


        int i = studentService.getPresentStudentCount(studentParam);
        assertEquals(0, i);

    }
}

您还应该在单元测试中配置studentInstitutionMapper的行为,以使其返回预期结果。