微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决使用构建器模式和 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 举报,一经查实,本站将立刻删除。