我很难让我的JUnit测试工作。以下是代码段。 第一个是我的超类:
@MappedSuperclass
abstract class IdentifiedEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
...
}
然后有两个下属:
@Entity
@Table(name = "\"user\"")
@AttributeOverride(name = "id", column = @Column(name = "user_id"))
public class User extends IdentifiedEntity {
...
}
和
@Entity
@Table(name = "meal")
@AttributeOverride(name = "id", column = @Column(name = "meal_id"))
public class Meal extends IdentifiedEntity {
@ManyToOne(optional = false)
@JoinColumn(name = "user_id")
private final User user;
...
@Override
public String toString() {
return getClass().getSimpleName() + '#' + getId() + "U#" + user.getId()
+ ':' + desc + '@' + when + '×' + calories;
}
}
这是脚本,在PostgreSQL中创建DB(一个例外):
create table "user" (
user_id serial primary key,
...
);
和
create table meal (
meal_id serial primary key,
user_id int not null references "user"(user_id),
...
);
最后是测试用例(其中的一部分):
@ContextConfiguration("classpath:/spring/spring-app.xml")
@Sql("classpath:/db/refill.sql")
@RunWith(SpringRunner.class)
@Transactional(REQUIRED)
public class JpaMealRepositoryImplTest {
@Test
public void updateWithValidMeal() throws Exception {
meal.setId(ID_MEAL_ADMINS);
repo.update(meal);
}
}
repo
是
@Repository
public final class JpaMealRepositoryImpl implements MealRepository {
@Override
public void update(Meal meal) throws NotFoundException {
log.info("update({})", meal);
Preconditions.checkArgument(!meal.isNew(), "new");
Meal m = em.find(Meal.class, meal.getId());
log.debug("m={}", m);
if (m == null || m.getUser().getId() != meal.getUser().getId()) {
throw new NotFoundException("mealId=" + meal.getId() + "; userId=" + meal.getUser().getId());
}
m.setWhen(meal.getWhen());
m.setDesc(meal.getDesc());
m.setCalories(meal.getCalories());
}
}
小心,现在是尖叫:日志
190216.874 I main/JpaMealRepositoryImpl - update(Meal#4U#1:Перекус@2018-01-26T19:02×300)
Hibernate:
select
meal0_.meal_id as id1_0_0_,
meal0_.calories as calories2_0_0_,
meal0_."desc" as desc3_0_0_,
meal0_.user_id as user_id5_0_0_,
meal0_."when" as when4_0_0_,
user1_.user_id as id1_1_1_,
user1_.admin as admin2_1_1_,
user1_.calories_per_day_limit as calories3_1_1_,
user1_.email as email4_1_1_,
user1_.enabled as enabled5_1_1_,
user1_.name as name6_1_1_,
user1_.password as password7_1_1_,
user1_.registered_at as register8_1_1_
from
meal meal0_
inner join
"user" user1_
on meal0_.user_id=user1_.user_id
where
meal0_.meal_id=?
190216.877 D main/JpaMealRepositoryImpl - m=null
ru.javawebinar.topjava.repository.NotFoundException: mealId=4; userId=1
at ru.javawebinar.topjava.repository.jpa.JpaMealRepositoryImpl.update(JpaMealRepositoryImpl.java:38)
at ru.javawebinar.topjava.repository.jpa.JpaMealRepositoryImplTest.updateWithValidMeal(JpaMealRepositoryImplTest.java:61)
...
问题是:为什么190216.877 D main/JpaMealRepositoryImpl - m=null
如果我在Postgres中运行此查询,将?
替换为meal_id
(日志中显示为4
),那么我会得到一行。只是我想要的一行。为什么em.find(...)
会返回null
?
想法?
谢谢大家!
更新
我在启动每个测试类时使用refill.sql
脚本填充数据库:
@Sql("classpath:/db/refill.sql")
以下是我在psql
中发出的qwery:
select
meal0_.meal_id as id1_0_0_,
meal0_.calories as calories2_0_0_,
meal0_."desc" as desc3_0_0_,
meal0_.user_id as user_id5_0_0_,
meal0_."when" as when4_0_0_,
user1_.user_id as id1_1_1_,
user1_.admin as admin2_1_1_,
user1_.calories_per_day_limit as calories3_1_1_,
user1_.email as email4_1_1_,
user1_.enabled as enabled5_1_1_,
user1_.name as name6_1_1_,
user1_.password as password7_1_1_,
user1_.registered_at as register8_1_1_
from
meal meal0_
inner join
"user" user1_
on meal0_.user_id=user1_.user_id
where
meal0_.meal_id=4;
结果是
4|400|Завтрак|1|2017-12-11 10:00:00|1|t|2000|admin@example.com|t|Admin|\x21232f297a57a5a743894a0e4a801fc3|2018-01-26 22:37:08.326818+00
答案 0 :(得分:0)
首先,测试应该在隔离的环境中运行,而不是在每次运行时清除数据库。
如果您希望测试删除当前的PostgreSQL架构,那么您应该只使用Hibernate hibernate.hbm2ddl.auto
配置属性。
如果您不希望Hibernate更改架构,则不应设置hibernate.hbm2ddl.auto
属性。
但是,你要在每次运行时回滚吗?你是如何在这样的环境中工作的。
最好从一个干净的模式开始,用数据填充它,进行测试,最后清除它,因为你不想留下可能干扰其他测试的数据。
答案 1 :(得分:0)
民间!
我以这种方式解决了这个问题。
正如我写的原始超类是
@MappedSuperclass
abstract class IdentifiedEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
...
}
和recreate.sql
create table "user" (
user_id serial primary key,
...
);
create table meal (
meal_id serial primary key,
user_id int not null references "user"(user_id),
...
);
此修复程序位于strategy
的{{1}}。这是续订的@GeneratedValue(strategy = GenerationType.IDENTITY)
:
IdentifiedEntity
(@MappedSuperclass
@Access(FIELD)
abstract class IdentifiedEntity {
@Id
@SequenceGenerator(name = "seqgen", sequenceName = "sequencer")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seqgen")
private int id;
...
}
是可选的)
和@Access(FIELD)
recreate.sql
和create sequence sequencer;
create table "user" (
user_id int primary key default nextval('sequencer'),
...
);
create table meal (
meal_id int primary key default nextval('sequencer'),
user_id int not null references "user"(user_id),
...
);
refill.sql
在我看来,Hibernate中存在BUG,如果...
alter sequence sequencer restart 1;
...
再现。
谢谢你们!