初学者求助:NetBeans+Maven环境下JPA单元测试问题
嘿,作为单元测试新手,你用NetBeans 8.1 + Maven来测试PostgreSQL查询的这个场景我太熟悉了!下面给你一步步的实现指导,还有常见坑的解决方法:
首先要明确:单元测试应该尽量隔离真实生产数据库——既避免污染生产数据,也让测试不依赖外部环境(比如数据库是否可用)。当然如果要测真实的SQL查询逻辑,也可以用专门的测试数据库,这里两种方案都会覆盖。
1. 先配置Maven测试依赖
打开你的pom.xml,添加JUnit(NetBeans 8.1对JUnit 4支持更友好)、Mockito(用来Mock数据库相关对象)和PostgreSQL驱动的测试依赖:
<dependencies> <!-- JUnit核心依赖 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> <!-- Mockito:用来模拟EntityManager等对象,隔离真实数据库 --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>3.12.4</version> <scope>test</scope> </dependency> <!-- PostgreSQL驱动:如果要连接真实测试数据库的话需要 --> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.2.25</version> <scope>test</scope> </dependency> </dependencies>
2. 创建测试类
在src/test/java下创建和DatesUtil对应的测试类DatesUtilTest,这里分两种方案:
方案A:用Mockito隔离真实数据库(推荐新手先练这个)
这种方式不需要真的连接数据库,而是模拟EntityManager的行为,专注测试你的业务逻辑:
import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import javax.persistence.EntityManager; import javax.persistence.Query; import java.util.Arrays; import static org.junit.Assert.*; import static org.mockito.Mockito.*; public class DatesUtilTest { private DatesUtil datesUtil; // 模拟EntityManager对象 @Mock private EntityManager mockEntityManager; @Mock private Query mockQuery; @Before public void setUp() { // 初始化所有Mock对象 MockitoAnnotations.initMocks(this); datesUtil = new DatesUtil(); // 注意:你需要给DatesUtil里的static entityManager加一个可设置的入口,比如添加setter方法 // 比如在DatesUtil中添加: // public static void setEntityManager(EntityManager em) { // entityManager = em; // } // 然后这里替换成mock的对象 DatesUtil.setEntityManager(mockEntityManager); } @Test public void testMenuQuery() { // 1. 模拟查询返回的结果 Menusistema testMenu = new Menusistema(); testMenu.setNombre("测试菜单"); when(mockEntityManager.createQuery(anyString(), eq(Menusistema.class))) .thenReturn(mockQuery); when(mockQuery.getResultList()).thenReturn(Arrays.asList(testMenu)); // 2. 调用你要测试的方法(假设DatesUtil有一个查询方法叫getMenusByName) datesUtil.setNombreBuscar("测试菜单"); Collection<Menusistema> result = datesUtil.getMenusByName(); // 3. 断言结果符合预期 assertNotNull(result); assertFalse(result.isEmpty()); assertEquals("测试菜单", result.iterator().next().getNombre()); // 验证EntityManager的方法是否被正确调用 verify(mockEntityManager, times(1)).createQuery(anyString(), eq(Menusistema.class)); } }
方案B:连接真实测试数据库
如果要验证真实的SQL查询逻辑,你可以配置一个测试专用的PostgreSQL数据库,然后在测试前准备数据,测试后清理:
import org.junit.After; import org.junit.Before; import org.junit.Test; import javax.persistence.EntityTransaction; import static org.junit.Assert.*; public class DatesUtilTest { private DatesUtil datesUtil; private EntityTransaction transaction; @Before public void setUp() { datesUtil = new DatesUtil(); // 获取事务,准备插入测试数据 transaction = DatesUtil.entityManager.getTransaction(); transaction.begin(); // 插入测试数据 Menusistema testMenu = new Menusistema(); testMenu.setNombre("测试菜单"); DatesUtil.entityManager.persist(testMenu); transaction.commit(); } @Test public void testRealMenuQuery() { datesUtil.setNombreBuscar("测试菜单"); Collection<Menusistema> result = datesUtil.getMenusByName(); assertNotNull(result); assertEquals(1, result.size()); assertEquals("测试菜单", result.iterator().next().getNombre()); } @After public void tearDown() { // 清理测试数据 transaction = DatesUtil.entityManager.getTransaction(); transaction.begin(); DatesUtil.entityManager.createQuery("DELETE FROM Menusistema m WHERE m.nombre = '测试菜单'").executeUpdate(); transaction.commit(); } }
3. 在NetBeans中运行测试
右键点击DatesUtilTest类,选择Test File,NetBeans会通过Maven执行测试,你可以在底部的“Output”窗口看到测试结果——绿色的对勾就是测试通过啦!
问题1:EntityManager初始化失败,找不到Persistence Unit
解决:确保src/test/resources/META-INF下有persistence.xml,并且配置的persistence-unit名称和你代码里的com.controlpersonal.pu一致。测试环境的persistence.xml可以单独配置成测试数据库,别和生产的混在一起。问题2:测试依赖真实数据库,导致测试不稳定(比如数据库挂了就跑不了)
解决:优先用方案A的Mockito模拟;或者换用嵌入式数据库(比如H2),在测试时自动创建临时库,测试完就销毁。示例persistence.xml配置:<persistence-unit name="com.controlpersonal.pu-test" transaction-type="RESOURCE_LOCAL"> <class>com.yourpackage.Menusistema</class> <properties> <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/> <property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1"/> <property name="javax.persistence.jdbc.user" value="sa"/> <property name="javax.persistence.jdbc.password" value=""/> <property name="hibernate.hbm2ddl.auto" value="create-drop"/> </properties> </persistence-unit>问题3:NetBeans里测试类找不到主类的依赖
解决:检查Maven依赖的scope——主类的依赖如果是compile范围,测试类会自动继承;如果是provided范围,需要在testscope也添加对应依赖。问题4:测试数据准备/清理太麻烦
解决:可以用DBUnit工具来管理测试数据集,在@Before时导入测试数据,@After时清空,比手动写SQL方便多了。
内容的提问来源于stack exchange,提问作者Fernando Pie

