java - 测试期间的 Spring Boot JPA 事务 - 在插入时不抛出关键违规异常

标签 java spring spring-boot spring-data-jpa

我进行了以下测试,生成带有公司 ID 和电子邮件的邀请。然后,我们使用相同的公司 ID 和电子邮件生成第二个。这应该违反数据库的唯一约束(请参阅邀请实体)。事实是,测试通过了,如下所示(我猜第二次插入时永远不会提交事务)

如果我在第二次插入后执行 findAll() (请参阅下面的注释),我会在 findAll() 是索引的行上得到一个异常发生违规。

如何让 UserService 中的方法在方法返回时提交其事务,以便测试代码按原样抛出异常?

@RunWith(SpringRunner.class)
@DataJpaTest
public class UserServiceTest {
    ... Everything is autowired
    @Test
    public void testCreateInvitation() {
        String email = "test2@example.com";
        Company company = userService.createCompany("ACMETEST", tu);

        assertTrue(invitationRepository.count() == 0l);
        assertNotNull(userService.sendInvitation(company, email));
        assertTrue(invitationRepository.count() == 1l);

        assertTrue(invitationRepository.findAllByEmail(email).size() == 1);
        // Second should throw exception
        userService.sendInvitation(company, email);

        // If this line is uncommented, I get key violation exception, otherwise, test passes!!!!????
        //Iterable<Invitation> all = invitationRepository.findAll();
    }

邀请类别和约束:

@Entity
@Table(uniqueConstraints=@UniqueConstraint(columnNames={"email", "company_id"}))
@JsonIdentityInfo(generator= ObjectIdGenerators.PropertyGenerator.class, property="id")
@Data
public class Invitation {

    @Id
    @GeneratedValue(generator="system-uuid")
    @GenericGenerator(name="system-uuid", strategy = "uuid")
    String id;

    @ManyToOne
    @JoinColumn(name="company_id")
    private Company company;

    String email;

    Date inviteDate;

    Date registerDate;
}

用户服务:

@Service
@Transactional(propagation = Propagation.REQUIRES_NEW)
public class UserService {
    public Invitation sendInvitation(Company company, String toEmail) {
        Invitation invitation = new Invitation();
        invitation.setCompany(company);
        invitation.setInviteDate(new Date());
        invitation.setEmail(toEmail);
        try {
            // TODO send email
            return invitationRepository.save(invitation);
        } catch (Exception e) {
            LOGGER.error("Cannot send invitation: {}", e.getMessage());
        }
        return null;
    }
}

最佳答案

How do I make the methods in the UserService commit their transactions when the method returns, so the test code will throw an exception as-is?

@DataJpaTest@Transactional本身。代码写在 @Test方法在事务内执行。您可以使用 Propogation.NOT_SUPPORTED 更改它其中

Execute non-transactionally, suspend the current transaction if one exists

@Test
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void testCreateInvitation() {
    // your test method body unchanged
}

使用这个你应该在第二个 userService.sendInvitation(company, email); 上得到一个异常打电话。

还有一些其他选项。

选项 1:

添加@Commit您的测试方法。

所有测试都标有 @Transactionalrolled back执行后。但 Hibernate 有一个微妙的问题:它可能会延迟执行 sql,直到您提交事务(或显式调用 flush (选项 2))。

由于事务回滚,因此没有执行任何插入操作,因此不存在约束违规。

请注意使用@Commit您将在测试方法外部抛出异常。

选项 2:

使用手册flush() :

如果您的存储库 extends JpaRepository<> :

@Test
public void testCreateInvitation() {
    // create first invitation,
    // create second invitation
    invitationRepository.flush();
}

否则注入(inject)EntityManager并调用flush()关于它:

@PersistenceContext
private EntityManager em;

@Test
public void testCreateInvitation() {
    // create first invitation,
    // create second invitation
    em.flush();
}

invitationRepository.flush() 时,您将收到异常或em.flush()已调用。

选项 3: 使用 GenerationType.IDENTITY:

@Id
@GeneratedValue(strategy = IDENTITY)
private Long id;

Hibernate 必须将 id 分配给 @Entity在你之后save()它。但如果不执行insert,它就无法获取实体的ID。 .

附注 有件事让我困惑。

您使用@Transactional(propagation = Propagation.REQUIRES_NEW)并且它应该在方法执行后强制提交事务。请检查您的日志以查看交易是否真正有效。

关于java - 测试期间的 Spring Boot JPA 事务 - 在插入时不抛出关键违规异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52237602/

相关文章:

java - 在 swing 中单击按钮时显示 JfreeChart

java - Spring:检查每个端点上的标准查询参数

java - 如何在spring配置类中创建RestControllerAdvice类型的spring @bean

java - 如何检查Grails应用程序的GORM版本

spring-boot - 在 spring boot/spring data elasticsearch 中禁用自动索引创建

java - Elasticsearch 稳定版

java - 如何正确映射模糊处理程序方法?

java - Netbeans 中针对 Maven Web 应用程序的 UI 推荐

java - NoSuchMethodError 使用 Builder 将 Avro 对象写入 HDFS

java - hashcode() 和 equals() 在 java 中的工作?