[英]How to use Mockito to mock including an EntityManager
Currently in school we are working on a rather large project. 目前在学校,我们正在开展一个相当大的项目。 However testing in Java wasn't really explained that well so I didn't really work TDD like I was suppose to.
然而,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();
}
So my question is, how do I test this method using Mockito? 所以我的问题是,如何使用Mockito测试这种方法?
The getEntityManager
method is private and it invokes a static method so, as things stand, you would need to use PowerMockito to provide a mocked instance of EntityManager
in your test. getEntityManager
方法是私有的,它调用静态方法,因此,您需要使用PowerMockito在测试中提供EntityManager
的模拟实例。 For example: 例如:
@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);
}
}
However, you could simplify things, from a testing and design perspective, by externalising the creation of the entity manager into a factory, for example. 但是,您可以通过将实体管理器的创建外部化为工厂,从测试和设计的角度简化操作。
public class EntityManagerFactory {
public EntityManager create() {
return EntityController.getEntityManager();
}
}
Next, inject an instance of EntityManagerFactory
into whatever class contains getAllSkeletons()
(ie the class you are testing). 接下来,将
EntityManagerFactory
注入任何包含getAllSkeletons()
的类(即您正在测试的类)。 The simplest way of doing this is to declare it as a constructor argument: 最简单的方法是将它声明为构造函数参数:
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();
}
}
Now, you can test this code using vanilla mockito. 现在,您可以使用vanilla mockito测试此代码。 For example:
例如:
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
// ...
}
}
1) The EntityManager should not be associated to the controller : 1)EntityManager不应与控制器关联:
return EntityController.getEntityManager();
In terms of design, it is not desirable : low layer and high layer should not be mixed, otherwise why use them ? 在设计方面,不希望:低层和高层不应混合,否则为什么要使用它们?
In terms of testing for getAllSkeletons()
, this coupling will also make the unit test harder to set and to write. 在测试
getAllSkeletons()
,这种耦合也会使单元测试更难设置和写入。
2) The actual method doesn't have logic to test but the exception case : you just create a query, execute it and return the result. 2)实际方法没有测试逻辑但是例外情况:你只需创建一个查询,执行它并返回结果。
It is a good case for an integration test (without mocking the DB layer), less for an unit test. 对于集成测试(没有模拟DB层),这是一个很好的例子,对于单元测试来说则更少。
As it will make the unit test complex and with not a lot of value. 因为它会使单元测试变得复杂并且没有太多价值。
Example of what you could get with Mockito and that I don't recommend. 你可以用Mockito得到的例子以及我不推荐的例子。
Make the EntityManager
a dependency of the class under test : with injection or not. 使
EntityManager
成为被测试类的依赖关系:是否注入。
In your unit test, mock this dependency. 在您的单元测试中,模拟此依赖项。
It could look like : 它可能看起来像:
@Mock
EntityManager entityManagerMock;
@Test
public void getAllSkeletons(){
TypedQuery<ExamSkeleton> queryByMock = (TypedQuery<ExamSkeleton>) Mockito.mock(TypedQuery.class);
Mockito.when(entityManagerMock.createQuery("SELECT NEW ExamSkeleton (s.id, s.filename, s.course, s.visible) FROM ExamSkeleton as s"))
.thenReturn(queryByMock);
List<ExamSkeleton> skeletons = new ArrayList<>();
Mockito.when(queryByMock.getResultList())
.thenReturn(skeletons);
Foo foo = new Foo();
foo.setEntityManager(entityManagerMock);
// action
List<ExamSkeleton> actualSkeletons = foo.getAllSkeletons();
// assertion
Assert.assertSame(skeletons, actualSkeletons);
}
Really don't write this kind of code that just describes the flow of invocations. 真的不要写这种只描述调用流程的代码。
It makes just a test brittle that will very rarely catch regressions. 这只会使测试变得脆弱,很少会出现回归。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.