我有一个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
。这仅发生在模拟对象上。如何获得模拟对象的自动装配字段?
答案 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
类的源代码,我也可以提供模拟/真实实现。
这种类型的注入的另一个好处(构造函数注入与您在问题中使用的字段注入相反)不会破坏字段的封装。
注意:
我没有将@Autowired
放在构造函数上,因为在最新版本的spring中,只要有一个构造函数(对于单元测试而言,它根本不相关)就不需要了。
如果您担心构造函数的样板代码,可以使用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的行为,以使其返回预期结果。