简体   繁体   English

Spring Integration JPA存储库测试无法正常工作

[英]Spring integration jpa repository tests don't work as it should

I have something really strange. 我真的很奇怪 I want to test my repository level and I need to test if I can save 2 users with the same username(username field is unique in the database). 我想测试我的存储库级别,并且需要测试是否可以用相同的用户名保存2个用户(用户名字段在数据库中是唯一的)。 And there is my db configuration. 还有我的数据库配置。

spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url= jdbc:postgresql://localhost:5432/tutorial_test
spring.datasource.username=postgres
spring.datasource.password=root

# General JPA properties
spring.jpa.show-sql=false

#Note: The last two properties on the code snippet above were added to suppress an annoying exception
# that occurs when JPA (Hibernate) tries to verify PostgreSQL CLOB feature.
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false

# Hibernate Specific properties
spring.jpa.properties.hibernate.format_sql=false
spring.jpa.hibernate.ddl-auto=create

My entity class User: 我的实体类用户:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "users")
public class User {

    @Id
    @SequenceGenerator(name = "user_id_seq_gen", sequenceName = "user_id_seq", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_id_seq_gen")
    private Long id;
    @Column(nullable = false, unique = true, length = 50)
    @NotNull
    @Length(min = 4, max = 50)
    private String username;
    @Column(nullable = false, length = 50)
    @NotNull
    @Length(min = 6, max = 50)
    private String password;
    @Column(nullable = false, unique = true, length = 100)
    @NotNull
    @Length(min = 6, max = 50)
    private String email;
}

UserRepository: UserRepository:

public interface UserRepository extends JpaRepository<User, Long> {

    boolean existsByUsername(String username);
    boolean existsByEmail(String email);
    User findByUsername(String username);
}

And finally my test class: 最后是我的测试课:

@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@TestPropertySource("/application-test.properties")
public class UserRepositoryTest {

    @Autowired
    private UserRepository userRepository;

    @Before
    public void insertData() {
        user = new User(null, "Daimon", "123123", "krikkk998@mail.ru");
        userRepository.save(user);
    }

    @After
    public void cleanData(){
        user = null;
        userRepository.deleteAll();
    }

    @Test(expected = DataIntegrityViolationException.class)
    public void registerUserWithExistingUsername() {
        val user = new User(null, "Daimon", "123123", "glass999@mail.ru");
        userRepository.save(user);
    }

}

This test classes behavior is very strange. 这个测试类的行为很奇怪。 It throws an exception that it can't save another entity because the username is unique only after userRepository.deleteAll(); 它抛出一个例外,它无法保存另一个实体,因为用户名仅在userRepository.deleteAll();之后才是唯一的userRepository.deleteAll(); Why?? 为什么?? Ok, if I delete @After method, it doesn't throw the exception at all...And again, if I add System.out.println(userRepository.findAll()); 好的,如果我删除@After方法,它根本不会引发异常……再次,如果我添加System.out.println(userRepository.findAll()); after saving second user, it thowrs exception... What is going on here?? 保存第二位用户后,它发出异常消息...这是怎么回事? These all method works well when I start an application. 当我启动应用程序时,所有这些方法都能很好地工作。 But in these integration repositories tests something wrong. 但是在这些集成库中测试了一些错误。 I have another repository tests class where I can save parent object with a set of UNSAVED childs, and when I select parent object from the database, it gives me set of childs with NULL ids... I don't know what is the problem, but I think maybe in configuration?? 我还有另一个存储库测试类,可以在其中保存带有一组未保存子项的父对象,当我从数据库中选择父对象时,它为我提供了一组具有NULL ID的子项...我不知道这是什么问题,但我认为也许是在配置中? Because I repeat, there is no problem when I start application and all works very well. 因为我重复了,所以当我启动应用程序时没有问题,并且一切都很好。 I would be glad if you help me. 如果您能帮助我,我会很高兴。

What you see is a side effect of how JPA gets implemented. 您所看到的是如何实现JPA的副作用。 When you persist or merge an entity most people think of it as saving the entity. 当您persistmerge实体时,大多数人会认为它是保存实体。 And that's why the Repository method which calls these methods is called save . 这就是为什么调用这些方法的Repository方法称为save

But there is no insert to the database happening at that stage (1). 但是在该阶段没有发生数据库插入操作(1)。 Instead the entity is just tracked and it will get flushed on certain events: 而是只跟踪实体,并且在某些事件中它将刷新:

  1. A commit of the transaction. 事务的提交。
  2. An explicit call of flush. 显式调用flush。
  3. Depending on your configuration, possibly before a query (which seems to be the case here). 根据您的配置,可能在查询之前(这里似乎是这种情况)。 That is why you get the exception on calling findAll . 这就是为什么在调用findAll会出现异常的原因。 The implementation of deleteAll actually involves a findAll so it triggers the exception as well. deleteAll的实现实际上涉及到findAll因此它也会触发异常。

(1) actually, an insert might happen depending on your ID generation strategy. (1)实际上,取决于您的ID生成策略,可能会发生insert

@Before runs before your test is run. @Before运行,然后运行测试。 Here it inserts a User with the Username 'Daimon' 它在此处插入一个用户名为“ Daimon”的用户

@Test is your test. @Test是您的测试。 It tries to insert a user with the username 'Daimon' which already exists (because it was inserted in @Before . This is why the exception is thrown. 它尝试插入一个用户名已经存在的用户“ Daimon”(因为它已插入@Before 。这就是抛出异常的原因。

@After runs after your test. @After在测试后运行。 It deletes all users. 它删除所有用户。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM