java - Mocktio 可以模拟持久性提供程序,以便 jenkins(或其他管道工具)可以在没有数据库的情况下执行 JUnit 测试吗?
问题描述
所以我为直接使用 DAO 的 API 编写了 JUnit 测试,包括 Mockito。EntityManager
和的模拟EntityTransaction
没有问题,测试在机器上运行良好,持久性提供程序可以连接到数据库。(使用EclipseLink)
然而,同样在运行这些测试的 Jenkins 无法访问相关数据库。每次詹金斯执行我得到的测试时:
No Persistence provider for EntityManager named XYZ
我确实理解这是由于 jenkins 无法与数据库建立真正的连接。这种行为是故意的,不应改变。
因此,我的问题是:是否可以模拟(使用 Mockito?)或以另一种方式伪造连接,以便可以EntityManagerFactory
使用伪造/持久性提供程序?
解决方案
在没有真正数据库访问的情况下测试封闭 API 的一种方法是构建、填充和拆除内存数据库以进行测试。Eclipselink 的 Spring & Derby 的简单设置是
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.transaction.TransactionConfiguration;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
@ContextConfiguration(classes = AppConfig.class)
@TransactionConfiguration(defaultRollback = false)
public abstract class AbstractContainer {
@PersistenceUnit(unitName = "PERSISTENT_UNIT_NAME")
protected EntityManagerFactory factory;
@Autowired
protected ApplicationContext applicationContext;
}
和
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter;
import java.util.Properties;
import javax.sql.DataSource;
@Configuration
public class AppConfig {
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em =
new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPersistenceUnitName("PERSISTENT_UNIT_NAME");
em.setPackagesToScan(new String[] { "package.name.to.scan" });
JpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
// here some additional properties for the PU
em.setJpaProperties(additionalProperties());
return em;
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("eclipselink.weaving", "false");
properties.setProperty("eclipselink.query-results-cache", "false");
properties.setProperty("eclipselink.cache.shared.default", "false");
properties.setProperty("javax.persistence.jdbc.driver",
"org.apache.derby.jdbc.EmbeddedDriver");
properties.setProperty("javax.persistence.jdbc.url",
"jdbc:derby:memory:NAME;create=true");
properties.setProperty("javax.persistence.jdbc.url", "jdbc:derby:PATH");
properties.setProperty("javax.persistence.jdbc.user", "");
properties.setProperty("javax.persistence.jdbc.password", "");
properties.setProperty("javax.persistence.sql-load-script-source",
"META-INF/sql/createDB.sql");
properties.setProperty("eclipselink.deploy-on-startup", "true");
properties.setProperty("eclipselink.target-database", "Derby");
return properties;
}
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
try {
Class.forName("org.eclipse.persistence.jpa.PersistenceProvider");
Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance();
} catch (ClassNotFoundException cnfe) {
cnfe.printStackTrace();
} catch (InstantiationException inste) {
inste.printStackTrace();
} catch (IllegalAccessException iace) {
iace.printStackTrace();
}
dataSource.setDriverClassName("org.apache.derby.jdbc.EmbeddedDriver");
dataSource.setUrl("jdbc:derby:memory:NAME;create=true");
dataSource.setUsername("");
dataSource.setPassword("");
return dataSource;
}
}
SQL 脚本位于test/resources/META-INF/sql/createDB.sql下。
最后,您的测试类使用SpringJUnit4ClassRunner.class Runner 扩展抽象容器并启动本地事务。
@RunWith(SpringJUnit4ClassRunner.class)
public class DAOTest extends AbstractContainer {
@Test
public void testDAO() {
EntityManager em = factory.createEntityManager();
em.getTransaction().begin();
}
}
默认情况下,测试的持久性单元在test/resources/META-INF/下。
使用 Maven 的依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>[4.1.7.RELEASE]</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>[4.1.7.RELEASE]</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>[4.1.7.RELEASE]</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-mock</artifactId>
<version>[2.0.8]</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.11.1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.11.1.1</version>
<scope>test</scope>
</dependency>
推荐阅读
- java - 从不同的文件夹加载 Jar 文件
- reactjs - 反应原生 SectionList 优化更大的列表
- c# - 为什么客户端不能以 xamarin 形式工作
- c++ - const char* 不能用作 std::char_traits 的常量值
::长度 - common-lisp - 在 common lisp 中实现字典
- javascript - How to keep my React code from being minified on Github?
- r - R:使用“for”循环和“case_when”检查多个变量。
- mysql - SQLSTATE[HY000] [2002] 连接被拒绝 (SQL: select * from information_schema.tables where table_schema = ms_api_shop
- r - 选择文件所在的父目录后,如何在 r shiny 中使用 reactivePoll 检查文件是否存在
- css - sass --watch 不关注更新(仅在首次运行时更新)