Я использую Maven, Hibernate и Spring в своем приложении. Я реализовал классы сущностей, классы DAO и классы обслуживания в своих собственных пакетах. У меня проблема при тестировании сервиса. При модульном тестировании метода DAO, который вызывает эта конкретная служба, ожидается результат. Но при тестировании метода обслуживания, использующего этот метод DAO, я не получаю тот же результат. Я думаю, что эта проблема связана с интеграцией. Сервис помечен @Transactional. Источник данных и сервис помечены @Autowired в классе тестирования сервиса. Я приложил контекстную конфигурацию класса тестирования сервиса.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-2.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="class1Dao"
class="org.project.datalayer.implementation.Class1DaoImplementation">
</bean>
<bean id="service"
class="org.project.services.implementation.Service1Implementation">
<property name="class1Dao">
<ref bean="class1Dao" />
</property>
</bean>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName"
value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:project" />
<property name="username" value="username" />
<property name="password" value="password" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
</bean>
<context:annotation-config />
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory"
ref="entityManagerFactory" />
</bean>
<tx:annotation-driven />
</beans>
Пример кода по запросу:
Сущность
@MappedSuperclass
public abstract class ClassBase implements Serializable {
@Id()
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Integer id;
@Version
private int version = 0;
private Date created;
private Date updated;
/**
* @return the id
*/
public Integer getId() {
return id;
}
@PrePersist
@Column(name = "created", nullable = false)
protected void onCreate() {
this.created = new Date();
}
@PreUpdate
@Column(name = "updated", nullable = false)
protected void onUpdate() {
this.updated = new Date();
}
/**
* @return the version
*/
public int getVersion() {
return this.version;
}
/**
* @param version the version to set
*/
public void setVersion(int version) {
this.version = version;
}
/**
* @return the created
*/
public Date getCreated() {
return this.created;
}
/**
* @return the updated
*/
public Date getUpdated() {
return this.updated;
}
}
@Entity
@Table(name = "class1")
class Class1 extends ClassBase {
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "class1_id")
private List<Class2> class2List = new ArrayList<Class2>();
@OneToMany(mappedBy = "class1", cascade = CascadeType.ALL)
private List<Class1Class4> class1Class4List = new ArrayList<Class1Class4>();
}
@Entity
@Table(name = "class1_class4")
class Class1Class4 extends ClassBase {
@ManyToOne(optional = false, cascade = CascadeType.ALL)
@JoinColumn(name="class4_id")
private Class4 class4;
@ManyToOne(optional = false, cascade = CascadeType.ALL)
@JoinColumn(name="class1_id")
private Class1 class1;
}
@Entity
@Table(name = "class2")
class Class2 extends ClassBase {
@OneToMany(mappedBy = "class1", cascade = CascadeType.ALL)
private Class1 class1;
@OneToMany(mappedBy = "class2", cascade = CascadeType.ALL)
private List<Class2Class3> class2Class3List = new ArrayList<Class2Class3>();
}
@Entity
@Table(name = "class2_class3")
class Class2Class3 extends ClassBase {
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "class2_id")
private Class2 class2;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "class3_id")
private Class3 class3;
}
@Entity
@Table(name = "class3")
class Class3 extends ClassBase {
@OneToMany(mappedBy = "class3", cascade = CascadeType.ALL)
private List<Class2Class3> class2Class3List = new ArrayList<Class2Class3>();
@OneToOne(cascade = CascadeType.ALL)
@JoinColumns({
@JoinColumn(name = "class4_id",
referencedColumnName = "id")
})
private Class4 class4;
@ManyToOne(cascade = CascadeType.ALL)
@ForeignKey(name = "fk_class3_to_parent", inverseName = "fk_parent_to_class3")
private Class3 parent;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private Set<Class3> descendantList = new HashSet<Class3>();
...
}
@Entity
@Table(name = "class4")
class Class4 extends ClassBase {
@OneToOne(mappedBy="class4")
private Class3 class3;
@OneToMany(mappedBy = "class4", cascade = CascadeType.ALL)
private List<Class1Class4> class1Class4List = new ArrayList<Class1Class4>();
}
DAO
public class Class1DaoImplementation extends BaseDaoTemplate<Class1> implements Class1Dao {
public Class1DaoImplementation() {
super(Class1.class);
}
public Class getPublicByPrimaryKey(Integer id) {
EntityManager em = getEntityManager();
Query q =
em.createQuery("SELECT distinct(p) FROM Class1 p"
+ " INNER JOIN p.class5 ps"
+ " INNER JOIN FETCH p.class2 it"
+ " INNER JOIN FETCH it.class2Class3List itfs"
+ " INNER JOIN FETCH itfs.class3 f"
+ " LEFT JOIN FETCH f.parent fp" // PROBLEM: null when running integration test
+ " LEFT JOIN FETCH f.descendants fd"
+ " WHERE p.id = :class1Id"
+ " AND ps.id = 5"
+ " ORDER BY p.id"
);
q.setParameter("class1Id", id);
return (Class1) q.getSingleResult();
}
}
Может ли проблема быть связана со сложностью запроса метода getPublicByPrimaryKey? Но если метод работает нормально во время модульных тестов, почему он работает по-другому при выполнении интеграционных тестов?
Данные испытаний:
<?xml version='1.0' encoding='UTF-8'?>
<dataset>
<!--ELEMENT CLASS3 EMPTY-->
<!--ATTLIST CLASS3
PARAM1 CDATA #REQUIRED
ID CDATA #REQUIRED
PARAM2 CDATA #REQUIRED
PARENT_ID CDATA #IMPLIED
-->
]>
<class3 param1="0" id="1" param2="5" />
<class3 param1="0" id="2" param2="5" />
<class3 param1="0" id="3" param2="5" parent_id="1" />
<class3 param1="0" id="4" param2="5" parent_id="1" />
<class3 param1="0" id="5" param2="5" parent_id="2" />
Загрузка данных испытаний:
Соединение соединение =
DataSourceUtils.getConnection (DataSource);
ArrayList<String> dbunitFilePaths = new ArrayList<String>();
dbunitFilePaths.add("/class3.xml");
ListIterator<String> dbunitFilePathsIterator = dbunitFilePaths.listIterator();
try {
IDatabaseConnection dbUnitConnection =
new DatabaseConnection(connection);
String dbunitFilePath;
ClassPathResource xml;
IDataSet[] dataSets = new IDataSet[dbunitFilePaths.size()];
for(int i = 0; i < dbunitFilePaths.size(); i++) {
dbunitFilePath = dbunitFilePathsIterator.next();
xml = new ClassPathResource(dbunitFilePath);
dataSets[i] = new FlatXmlDataSetBuilder().build(xml.getInputStream());
}
CompositeDataSet compositeDataSet = new CompositeDataSet(dataSets);
DatabaseOperation.CLEAN_INSERT.execute(dbUnitConnection,
compositeDataSet);
} finally {
DataSourceUtils.releaseConnection(connection, dataSource);
}
Если я отредактирую метод загрузки файла следующим образом ...
...
ListIterator<String> dbunitFilePathsIterator = dbunitFilePaths.listIterator();
FlatXmlDataSetBuilder flatXmlDataSetBuilder;
try {
...
xml = new ClassPathResource(dbunitFilePath);
flatXmlDataSetBuilder = new FlatXmlDataSetBuilder().setColumnSensing(true);
dataSets[i] = flatXmlDataSetBuilder.build(xml.getInputStream());
}
...
... Затем я получаю следующее сообщение для всех, НО первый метод тестирования:
java.sql.SQLException: Integrity constraint violation FK_CLASS3_TO_PARENT table: CLASS3