gpt4 book ai didi

java - 运行单元测试时奇怪的 java 外键约束失败

转载 作者:行者123 更新时间:2023-11-29 20:52:11 25 4
gpt4 key购买 nike

因此,由于在尝试对服务进行单元测试时遇到问题,我最近一直在碰壁。

我有一个用户,它与产品、客户和报价类有多个单向关系。我将 SpringBoot 与 Spring JPA 存储库结合使用,使用 Hibernate 作为 ORM 对 MySQL 数据库执行操作。

我还有不同的服务调用存储库来对数据库执行这些操作,我正在尝试对这些服务进行单元测试。

当我单独运行单元测试类时,它们都成功,没有问题,但是当我一起运行它们时,QuotationService 测试完全失败。但值得注意的是,它们总是在 CustomerService 测试之后运行。

查看堆栈跟踪后,我发现当我尝试将引用保存到测试类中的数据库时,由于外键约束,每个测试都会失败。

Caused by: java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`kmobeheerdb`.`quotation`, CONSTRAINT `FK_fq5x6je1sicnskcj35yqhp85g` FOREIGN KEY (`quotation_id`) REFERENCES `user` (`user_id`))
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:683)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:663)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:653)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:108)
at com.mysql.cj.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2061)
at com.mysql.cj.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1819)
at com.mysql.cj.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2033)
at com.mysql.cj.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:1969)
at com.mysql.cj.jdbc.PreparedStatement.executeLargeUpdate(PreparedStatement.java:4953)
at com.mysql.cj.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1954)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:208)
... 105 more

当我尝试保存新报价时,测试总是失败的部分是在 @Before 部分。

@Autowired private QuotationService quotationService;
@Autowired private UserService userService;

private User user;
private Quotation quotation;

@Before
public void setup() throws UserServiceException, QuotationServiceException {
String userEmail = "tzestermail@mail.com";
String userName = "testername";

User newUser = new User(userEmail, userName);
user = userService.register(newUser);

//Tests fail on the createQuotation statement beneath
Quotation newQuotation = new Quotation();
quotation = quotationService.createQuotation(newQuotation, user.getUserId());

user = userService.getUser(user.getUserId());

assertNotNull(user);
assertNotNull(quotation);
assertEquals(1, user.getQuotations().size());
}

我进行了很多搜索以尝试解决此问题,包括使关系成为双向,但没有任何效果,并且错误仍然存​​在。

供引用:

用户类别:

@Entity
@Table(name = "user", uniqueConstraints = {
@UniqueConstraint(name = "UX_user_email", columnNames = {"email"})
})
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "user_id", nullable = false)
private int userId;
private String email;
private String password;

@OneToMany(fetch = FetchType.EAGER, mappedBy = "productId", orphanRemoval = true)
private Set<Product> products;

@OneToMany(fetch = FetchType.EAGER, mappedBy = "quotationId", orphanRemoval = true)
private Set<Quotation> quotations;

@OneToMany(fetch = FetchType.EAGER, mappedBy = "customerId", orphanRemoval = true)
private Set<Customer> customers;

public User(String email, String password) {
this.email = email;
this.password = password;
}

public User() {
}

public void addQuotation(Quotation quotation){
if(quotation != null){
if(quotations == null){
quotations = new HashSet<>();
}
quotations.add(quotation);
}
}

public void removeQuotation(Quotation quotation){
if(quotation != null && quotations.contains(quotation)){
quotations.remove(quotation);
}
}

//Omitted getters and setters
}

报价类别:

@Entity
public class Quotation {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "quotation_id", nullable = false)
private int quotationId;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "productId", cascade = CascadeType.PERSIST)
private Set<Product> products;

private double routeTotal;
private double total;
private String memo;

//Omitted getters and setters
}

报价服务:

@Transactional(rollbackFor = QuotationServiceException.class)
@Service
public class QuotationServiceImpl implements QuotationService {
private Logger logger = LogManager.getLogger();
@Autowired private ExceptionStrings exceptionStrings;
@Autowired private UserService userService;
@Autowired private QuotationRepository quotationRepository;

@Override
public Quotation createQuotation(Quotation quotation, int userId) throws QuotationServiceException {
if (quotation == null || userId == 0 || userService.getUser(userId) == null) {
logger.error(exceptionStrings.createQuotationInputError);
throw new QuotationServiceException(exceptionStrings.createQuotationInputError);
}
try {
User user = userService.getUser(userId);
user.addQuotation(quotation);
return quotationRepository.save(quotation);
} catch (DataIntegrityViolationException e) {
logger.error(exceptionStrings.createQuotationError);
throw new QuotationServiceException(exceptionStrings.createQuotationError, e);
}
}
}

最佳答案

我很确定我找到了问题的解决方案。正如斯科特·韦尔登(Scott Weldon)建议的那样,我检查了我的数据库是否在每次运行时都被重置。我的 hibernate 配置为 create-drop,但似乎我还需要通过放置来强制 Spring 配置重新加载

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)

在每个测试类之上。

这解决了我的问题。

关于java - 运行单元测试时奇怪的 java 外键约束失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37949331/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com