如何使用 Mockito 来模拟包括 EntityManager

Bjo*_*ops 4 java unit-testing mockito

目前在学校,我们正在做一个相当大的项目。然而,Java 中的测试并没有真正得到很好的解释,所以我并没有像我想象的那样真正使用 TDD。

protected EntityManager getEntityManager() {
    return EntityController.getEntityManager();
}

// Get all exam skeletons from the DB
@Override
public List<ExamSkeleton> getAllSkeletons() {
    EntityManager entityManager = getEntityManager();
    try {
        TypedQuery<ExamSkeleton> query = entityManager.createQuery("SELECT NEW ExamSkeleton (s.id, s.filename, s.course, s.visible) FROM ExamSkeleton as s", ExamSkeleton.class);

        List<ExamSkeleton> skeletons = query.getResultList();

        return skeletons;
    } catch (IllegalArgumentException exception) {
        LOGGER.error(exception);
    }
        return Collections.emptyList();
}
Run Code Online (Sandbox Code Playgroud)

所以我的问题是,如何使用 Mockito 测试这种方法?

gly*_*ing 5

方法1:测试代码原样

getEntityManager方法是私有的,它调用一个静态方法,因此,就目前情况而言,您需要使用 PowerMockitoEntityManager在您的测试中提供一个模拟实例。例如:

@RunWith(PowerMockRunner.class)
@PrepareForTest({EntityController.class})
public class SomeTest {

    @Test
    public void aTest() {
        PowerMockito.mockStatic(EntityController.class);

        EntityManager entityManager = Mockito.mock(EntityManager.class);
        Mockito.when(EntityController.getEntityManager()).thenReturn(entityManager);

        TypedQuery<ExamSkeleton> query = (TypedQuery<ExamSkeleton>) Mockito.mock(TypedQuery.class);

        Mockito.when(entityManager.createQuery("SELECT NEW ExamSkeleton (s.id, s.filename, s.course, s.visible) FROM ExamSkeleton as s")).thenReturn(query);

        List<ExamSkeleton> expected = new ArrayList<>();
        Mockito.when(query.getResultList()).thenReturn(expected);

        ExamRepository examRepository = new ExamRepository();

        List<ExamSkeletons> actual = examRepository.getAllSkeletons();

        // this assertion verifies that getAllSkeletons gives you the result of the above SQl query
        assertSame(expected, actual);
    }
}
Run Code Online (Sandbox Code Playgroud)

方法 2:重构以分离关注点和易于测试

但是,您可以从测试和设计的角度简化事情,例如,通过将实体管理器的创建外部化为工厂。

public class EntityManagerFactory {

    public EntityManager create() {
        return EntityController.getEntityManager();
    }
} 
Run Code Online (Sandbox Code Playgroud)

接下来,将 的实例注入EntityManagerFactory到任何包含getAllSkeletons()的类(即您正在测试的类)中。最简单的方法是将其声明为构造函数参数:

public class SomeDao {
    private final EntityManagerFactory entityManagerFactory;

    public SomeDao(EntityManagerFactory entityManagerFactory) {
        this.entityManagerFactory = entityManagerFactory;
    }

    @Override
    public List<ExamSkeleton> getAllSkeletons() {
        try {
            TypedQuery<ExamSkeleton> query = entityManager.createQuery("SELECT NEW ExamSkeleton (s.id, s.filename, s.course, s.visible) FROM ExamSkeleton as s", ExamSkeleton.class);

            List<ExamSkeleton> skeletons = query.getResultList();

            return skeletons;
        } catch (IllegalArgumentException exception) {
            LOGGER.error(exception);
        }
            return Collections.emptyList();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以使用 vanilla mockito 测试此代码。例如:

public class SomeDaoTest {

    @Test
    public void canGetAllSkeletons() {
       EntityManagerFactory entityManagerFactory = Mockito.mock(EntityManagerFactory.class);

       Mockito.when(entityManagerFactory.create()).thenReturn(entityManager);

       SomeDao sut = new SomeDao(entityManagerFactory.class);

       // now SomeDao will use your mocked EntityManager so you can set expectations
       // on createQuery etc to drive your test scenarios
       // ...
    }
}
Run Code Online (Sandbox Code Playgroud)