Mockito - 模拟相同类型的通用对象

时间:2014-05-23 14:22:04

标签: java unit-testing junit mocking mockito

我正在尝试使用Mockito Framework 1.9.5和JUnit 4.11模拟我的GenericDao对象,但Mockito总是模拟第一个与该类型匹配的字段。同样符合名称也无济于事。

与API(http://docs.mockito.googlecode.com/hg-history/58d750bb5b94b6e5a554190315811f746b67f578/1.9.5/org/mockito/InjectMocks.html)中描述的一样,Mockito应该评估要模拟的正确字段。

预期输出:

EmployeeService.absenceDao -> null
EmployeeService.creditDao -> null
EmployeeService.employeeDao -> Mocked object

有效输出:

EmployeeService.absenceDao -> Mocked object
EmployeeService.creditDao -> null
EmployeeService.employeeDao -> nulll

重现这种情况的代码:

@RunWith(MockitoJUnitRunner.class)
public class EmployeeServiceTest {

    @InjectMocks
    EmployeeService employeeService;

    @Mock(name = "employeeDao")
    GenericDao<Employee> employeeDao;

    @Test
    public void testFindEmployeeByUsername() {
        // some tests
    }
}

我的模拟类,包含几个GenericDao字段,但我只是想模仿employeeDao

@Service
@Transactional
public class EmployeeService {
    @Autowired
    private GenericDao<Employee> employeeDao;
    @Autowired
    private GenericDao<Credit> creditDao;
    @Autowired
    private GenericDao<Absence> absenceDao;

1 个答案:

答案 0 :(得分:5)

根据我调试的内容,看起来Mockito无法通过注释处理类型参数。如果您遵循MockitoJunitRunner的堆栈跟踪,那么您最终会进入下面的DefaultAnnotationEngine是您想要查看的方法。

public void process(Class<?> clazz, Object testInstance) {
        Field[] fields = clazz.getDeclaredFields(); //This is the line of concern
        for (Field field : fields) {
            boolean alreadyAssigned = false;
            for(Annotation annotation : field.getAnnotations()) {           
                Object mock = createMockFor(annotation, field);
                if (mock != null) {
                    throwIfAlreadyAssigned(field, alreadyAssigned);                    
                    alreadyAssigned = true;                    
                    try {
                        new FieldSetter(testInstance, field).set(mock);
                    } catch (Exception e) {
                        throw new MockitoException("Problems setting field " + field.getName() + " annotated with "
                                + annotation, e);
                    }
                }        
            }
        }

我评论的这一行会在没有type参数的情况下拉回你的GenericDao。那么当它注入它时。现在它真的不重要因为你通常会嘲笑那个对象来控制返回的东西。但是在你的情况下,你有3个dao&#39; s意味着当你打电话给你的employeeDao并且模拟器在AbsenceDao上时它会抛出NullPointerException。我确实做了尝试:)。但如果你嘲笑这三个人。它过去了。现在我担心它实际上调用了正确的方法,所以我写了一些验证案例以确保。以下是我的所作所为。

GenericDAO

public interface GenericDao<T>
{
    public T getObject();
}

的EmployeeService

@Service
@Transactional
public class EmployeeService
{
    @Autowired
    private GenericDao<Absence>  absenceDao;
    @Autowired
    private GenericDao<Credit>   creditDao;
    @Autowired
    private GenericDao<Employee> employeeDao;


    public Absence getAbsenceObject()
    {
        return absenceDao.getObject();
    }

    public Credit getCreditObject()
    {
        return creditDao.getObject();
    }

    public Employee getEmployeeObject()
    {
        return employeeDao.getObject();
    }
}

EmployeeServiceTest

@RunWith(MockitoJUnitRunner.class)
public class EmployeeServiceTest
{
    @Mock
    private GenericDao<Absence>  absenceDao;
    @Mock
    private GenericDao<Credit>   creditDao;
    @Mock
    private GenericDao<Employee> employeeDao;
    @InjectMocks
    private EmployeeService      employeeService;

    @Test
    public void testGetObject()
    {
        Mockito.when(absenceDao.getObject()).thenReturn(new Absence());
        Mockito.when(creditDao.getObject()).thenReturn(new Credit());
        Mockito.when(employeeDao.getObject()).thenReturn(new Employee());

        Assert.assertNotNull(employeeService.getEmployeeObject());

        Mockito.verify(absenceDao, Mockito.never()).getObject();
        Mockito.verify(creditDao, Mockito.never()).getObject();
        Mockito.verify(employeeDao, Mockito.times(1)).getObject();
    }
}

我希望这会有所帮助。布拉沃我也学会了回答这个问题。