用@Transient 注释的字段被保存在@DataJpaTest 中
Field annotated with @Transient being persisted in @DataJpaTest
我正在练习 TDD,
所以现在我正在尝试进行暂时失败的测试。即将测试目前尚未映射字段关系的 @Entity
。所以我预计我的测试会失败。
这里是 TableA 实体,你可能会注意到 TableB 关系用 @Transient
注释,所以这个字段不会被持久化并且在 运行 其他集成测试时不会出错(测试使用 @RunWith(SpringRunner.class)
.
@Builder
@Table(name = "table_a")
@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class TableAData {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Setter
private String name;
@Transient
@Builder.Default
private List<TableBData> tableBs = List.of();
}
这是 TableB 实体的代码,没有什么有趣的地方。
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "table_b")
public class TableBData {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Setter
private String name;
}
我还有一个 TableAJpaRepository,它扩展了 JpaRepository<TableAData, Long>
:
public interface TableAJpaRepository extends JpaRepository<TableAData, Long> {
public Optional<TableAData> findByName(String name);
}
我的问题是:
为什么follow测试不下降?
@DataJpaTest
@RunWith(SpringRunner.class)
public class TableAJpaRepositoryIntegrationTest {
@Autowired
private TableAJpaRepository repository;
@Test
public void dataFechedByIdWhenGetTableBsShouldBringTableB() {
TableBData tableBItem = TableBData.builder()
.name("123 Test")
.build();
TableAData tableAItem = TableAData.builder()
.name("TableAEntryName")
.tableBs(List.of(tableBItem))
.build();
Long id = repository.save(archetype).getId();
repository.flush();
TableAData fetched = repository.getOne(id);
assertThat(fetched.getTableBs()).isNotEmpty(); // This should be falling
assertThat(fetched.getTableBs().get(0).getName()).isEqualTo("123 Test");
}
}
看起来 getTableBs 方法正在从关系中返回另一个 table 实体,但我没有映射它。我错过了什么吗?
所以我和我的朋友花了一些时间试图弄清楚发生了什么。我们找到了 this github issue that describes exactly the same issue. The person who open the issue also create a repo with a minimum reproducible example。
另一件很有帮助的事情是这个 SO 答案:.
看起来是因为缓存。
总而言之,解决方案是:
- 注入
TestEntityManager
以持久化并设置测试场景。
- 一直使用
TestEntityManager.persistAndFlush()
方法。
- 在开始测试之前调用
TestEntityManager.clear()
。
- 在测试用例中正常使用存储库。
我正在练习 TDD,
所以现在我正在尝试进行暂时失败的测试。即将测试目前尚未映射字段关系的 @Entity
。所以我预计我的测试会失败。
这里是 TableA 实体,你可能会注意到 TableB 关系用 @Transient
注释,所以这个字段不会被持久化并且在 运行 其他集成测试时不会出错(测试使用 @RunWith(SpringRunner.class)
.
@Builder
@Table(name = "table_a")
@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class TableAData {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Setter
private String name;
@Transient
@Builder.Default
private List<TableBData> tableBs = List.of();
}
这是 TableB 实体的代码,没有什么有趣的地方。
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "table_b")
public class TableBData {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Setter
private String name;
}
我还有一个 TableAJpaRepository,它扩展了 JpaRepository<TableAData, Long>
:
public interface TableAJpaRepository extends JpaRepository<TableAData, Long> {
public Optional<TableAData> findByName(String name);
}
我的问题是: 为什么follow测试不下降?
@DataJpaTest
@RunWith(SpringRunner.class)
public class TableAJpaRepositoryIntegrationTest {
@Autowired
private TableAJpaRepository repository;
@Test
public void dataFechedByIdWhenGetTableBsShouldBringTableB() {
TableBData tableBItem = TableBData.builder()
.name("123 Test")
.build();
TableAData tableAItem = TableAData.builder()
.name("TableAEntryName")
.tableBs(List.of(tableBItem))
.build();
Long id = repository.save(archetype).getId();
repository.flush();
TableAData fetched = repository.getOne(id);
assertThat(fetched.getTableBs()).isNotEmpty(); // This should be falling
assertThat(fetched.getTableBs().get(0).getName()).isEqualTo("123 Test");
}
}
看起来 getTableBs 方法正在从关系中返回另一个 table 实体,但我没有映射它。我错过了什么吗?
所以我和我的朋友花了一些时间试图弄清楚发生了什么。我们找到了 this github issue that describes exactly the same issue. The person who open the issue also create a repo with a minimum reproducible example。
另一件很有帮助的事情是这个 SO 答案:
看起来是因为缓存。
总而言之,解决方案是:
- 注入
TestEntityManager
以持久化并设置测试场景。 - 一直使用
TestEntityManager.persistAndFlush()
方法。 - 在开始测试之前调用
TestEntityManager.clear()
。 - 在测试用例中正常使用存储库。