spring-boot - Spring boot JPA 和 Transactional:无法通过单元测试重现错误
问题描述
我们有一种方法可以添加新记录(信用卡)并更新现有记录。更具体地说,我们将现有信用卡设置为 DISABLED 并添加一张新信用卡,创建为 ACTIVE。
@Service
@Transactional
public class CreditCardServiceImpl {
@Override
public CreditCard saveCard(Map<String, String> data, String cardType, String token, HashMap<String, String> card, String entityId, String fleetId, PspSettings pspSetting)
throws ParseException, ClientProtocolException, IOException, AdyenUnAuthorizedException, org.json.simple.parser.ParseException, AdyenException {
LOG.info("Check if creditCard exists for entityId#{}", entityId);
CreditCard creditCard = creditCardRepository.findByEntityIdAndStatus(entityId, CreditCardStatus.ACTIVE);
if (creditCard == null) {
creditCard = createCreditCard(data, cardType, token, card, entityId, fleetId);
} else {
LOG.info("Credit card#{} found, disable it and create a new one", creditCard.getId());
// disable the older card for this entity
creditCard.setStatus(CreditCardStatus.DISABLED);
creditCardRepository.save(creditCard);
// create a new card for this entity
creditCard = createCreditCard(data, cardType, token, card, entityId, fleetId);
// ***** SMELLLY ***
}
return creditCard;
}
调用此createCreditCard
方法:
private CreditCard createCreditCard(Map<String, String> data, String cardType, String token, HashMap card, String entityId, String fleetId) throws ParseException {
LOG.info("Creating new card");
CreditCard creditCard = new CreditCard();
creditCard.setCardSummary(data.get("cardSummary"));
creditCard.setFleetId(fleetId);
if (data.get("expiryDate") != null) {
creditCard.setExpiryDate(formatter.parse(data.get("expiryDate")));
}
creditCard.setCardType(cardType);
creditCard.setToken(token);
creditCard.setEntityId(entityId);
creditCard.setStatus(CreditCardStatus.ACTIVE);
if (card != null) {
creditCard.setHolderName((String) card.get("holderName"));
}
LOG.info("Saving card# {}", creditCard.toString());
creditCardRepository.save(creditCard);
return creditCard;
}
}
我们有一个错误,我们最终在 DB 中有两张相同的信用卡,都设置为 ACTIVE。
我怀疑这是因为我们重用了本地的 creditCard 变量。(参见上面的 *** SMELLY ** 行)
所以我认为这可以很容易地通过使用另一个本地变量而不是信用卡来解决。
令人不安的问题是我无法在单元测试中重现这一点。
以下测试通过。
@Test
public void disableAdyenTokenTest() {
//save a card first and then check that it exists to disable it
EntityX entityX = new EntityX();
// some stuff
entityX.setFleetId(BASE_FLEET);
entityX = entityService.save(entityX);
LOG.info("----- save credit card for test -----");
creditCardService.save(cc);
Map<String, String> data = new HashMap<String, String>();
String cardType="visa";
String newToken="0000000022";
HashMap card = new HashMap<String, String>();
Date date = new Date();
SimpleDateFormat formater = new SimpleDateFormat("mm/yyyy");
String dateString = formater.format(date);
data.put("expiryDate", dateString);
data.put("cardSummary", "cardSummary");
card.put("holderName", "Joe Louis");
CreditCard ccReturned = creditCardService.saveCard(data, cardType, newToken, card, entityX.getId(), BASE_FLEET, settings);
assertNotNull(ccReturned);
assertEquals(CreditCardStatus.ACTIVE, ccReturned.getStatus());
CreditCard activeCard = creditCardService.findByEntityIdAndStatus(entityX.getId(), CreditCardStatus.ACTIVE);
assertNotNull(activeCard);
CreditCard disabledCard = creditCardService.findByEntityIdAndStatus(entityX.getId(), CreditCardStatus.DISABLED);
assertNotNull(disabledCard);
List<PspTransaction> list = pspTransactionRepo.findAll();
assertNotNull(list);
}
知道如何在单元测试中重现此问题吗?
非常感谢您已经阅读了整篇文章:)
附录:
CreditCard 实体,ID 为 PK。
@Entity
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class CreditCard implements Serializable {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1L;
/** The id. */
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
……
更新
该应用程序使用 MariaDB 数据库运行,而单元测试在内存数据库中的 H2 上运行。这可能是为什么?
解决方案
推荐阅读
- operating-system - 比赛系统防止用户切换屏幕,如托业 IIG 比赛
- javascript - 如何将 node.js 文件中的变量导出到普通的 vanilla js 文件中
- javascript - 用 22 个单位和 3 个小数点限制文本
- javascript - uglify-js 是否支持 es6 及更高版本?
- tensorflow - 使用多层权重的正则化函数?
- ansible - 如何将 SSH 指纹添加到 Ansible 中的已知主机?
- arcgis - Arcgis - alterSpatialReference 时出错
- python - 等待协程与等待任务
- asp.net-core - 将 singin 与 Apple 与 Identity Server 4 集成
- azure - 具有私有 DNS 的 Azure API 管理服务