使用构建器模式和 JPA/Hibernate 创建的用于测试的持久嵌套或相关对象 更新 #1

问题描述

让我们看下面的类,它们是更复杂的类及其关系的简化。

@Data
@Builder
public class UserAccount {
    private String username;
    private String password;
    private Language contactLanguage;
    
    public static UserAccount.UserAccountBuilder defaultUserAccount() {
        return UserAccount.builder()
                .username("default_username")
                .password("default_password")
                .contactLanguage(defaultLanguage().build());
    } 
}

@Data
@Builder
public class Language {
    private String name;
    private String iso2;
    private String iso3;

    public static Language.LanguageBuilder defaultLanguage() {
        return Language.builder()
                .name("default_language_name")
                .iso2("default_iso2")
                .iso3("default_iso3");
    }
}

使用 Lombok 的 @Builder 注释,我可以轻松构建这样的对象,尤其是用于测试:

UserAccount.builder()
  .username("foo")
  .password("bar")
  .contactLanguage(Language.builder()
    .name("English")
    .iso2("EN")
    .iso3("ENG")
    .build())
  .build();

// Or even like this...

defaultUserAccount().build();

这适用于单元测试或任何此类生成的对象只需要存在于内存中的测试。

不过,我也想使用这种方法与底层数据库进行集成测试(使用 Spring Boot 2.4 + JPA + Hibernate)。这就是我目前无法解决的一些问题出现的地方。一起来看看:

每个 UserAccount 都需要有一个 contactLanguage,但 Language 独立存在。其他实体也可能使用它。使用 defaultUserAccount().build() 构建用户帐户时,由于 Language 对象尚未持久化,因此持久化此实体失败。 contactLanguage 上没有持久级联,因为我不希望在创建 Language 时创建“任何”UserAccount

我唯一的想法是使用 defaultLanguage().build() 并在 before defaultUserAccount().build() 之前坚持这个。但我觉得,一旦嵌套构建器的级别或与其他实体的关系更多,这将变得复杂和不稳定。

另一件事是:即使我设法坚持 defaultLanguge,一旦另一个测试调用 defaultUserAccount().build(),我就会遇到冲突,因为那样语言已经存在并且无法再次插入。

是否有任何模式或方法可以持久化此类测试数据对象?


更新 #1

经过多次搜索,我找到了看起来几乎相同的 this question on SO

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)