Spring boot JPA и Transactional: невозможно воспроизвести ошибку с помощью юнит-теста - PullRequest
0 голосов
/ 06 июня 2018

У нас есть метод, который добавляет новую запись (кредитную карту) и обновляет существующую запись.В частности, мы устанавливаем для существующей кредитной карты значение ОТКЛЮЧЕНО и добавляем новую, созданную как АКТИВНАЯ.

@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;
    }

}

У нас есть ошибка, в результате которой в БД мы имеем две идентичные кредитные карты, обе из которых установлены как АКТИВНЫЕ.

Я подозреваю, что это потому, что мы повторно используем локальную переменную creditCard.(см. строчку *** SMELLY ** выше)

Так что я думаю, что это легко исправить, используя другую локальную переменную вместо creditCard.

Проблема в том, что я не могу воспроизвести этов модульном тесте.

Следующий тест пройден.

@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);
    }

Есть идеи, как я могу воспроизвести эту проблему в модульных тестах?

Большое спасибо за то, что прочитали весь этот пост уже:)

ПРИЛОЖЕНИЕ:

Кредитная карта, с идентификатором 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 в памяти дБ.Может ли это быть причиной?

...