org.springframework.dao.DataIntegrityViolationException: could not execute statement [(conn=5) Data too long for column 'name' at row 1] [insert into members (created_at,deleted_at,email,name,provider,role,updated_at) values (?,?,?,?,?,?,?)]; SQL [insert into members (created_at,deleted_at,email,name,provider,role,updated_at) values (?,?,?,?,?,?,?)]
at app//org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:297)
at app//org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:256)
at app//org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:241)
at app//org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:560)
at app//org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at app//org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:343)
at app//org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:160)
at app//org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at app//org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:165)
at app//org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at app//org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:223)
at app/jdk.proxy3/jdk.proxy3.$Proxy201.save(Unknown Source)
at app//com.rejs.flashnote.domain.note.service.NoteGroupServiceIntegrationTest.deleteNoteGroup_Integration(NoteGroupServiceIntegrationTest.java:99)
at java.base@21.0.4/java.lang.reflect.Method.invoke(Method.java:580)
at java.base@21.0.4/java.util.ArrayList.forEach(ArrayList.java:1596)
at java.base@21.0.4/java.util.ArrayList.forEach(ArrayList.java:1596)
Caused by: org.hibernate.exception.DataException: could not execute statement [(conn=5) Data too long for column 'name' at row 1] [insert into members (created_at,deleted_at,email,name,provider,role,updated_at) values (?,?,?,?,?,?,?)]
https://naver.github.io/fixture-monkey/v1-0-0-kor/docs/introduction/overview/
테스트를 위한 데이터 생성에서 fixtureMoney를 사용한다.
에러 메시지를 보면 그 원인을 일목요연하게 파악할 수 있다.
entity의 ddl보다 긴 범위의 랜덤 데이터가 들어오게 된 것이다.
덱 삭제 통합 테스트: DB에서 해당 데이터가 완전히 제거되어야 한다
org.springframework.dao.DataIntegrityViolationException: could not execute statement [(conn=5) Duplicate entry 'z-google' for key 'uk_members_email_provider'] [insert into members (created_at,deleted_at,email,name,provider,role,updated_at) values (?,?,?,?,?,?,?)]; SQL [insert into members (created_at,deleted_at,email,name,provider,role,updated_at) values (?,?,?,?,?,?,?)]; constraint [uk_members_email_provider]
at app//org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:294)
at app//org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:256)
at app//org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:241)
at app//org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:560)
at app//org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at app//org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:343)
at app//org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:160)
at app//org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at app//org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:165)
at app//org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at app//org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:223)
at app/jdk.proxy3/jdk.proxy3.$Proxy208.save(Unknown Source)
at app//com.rejs.flashnote.domain.cards.service.DeckServiceTest.setup(DeckServiceTest.java:49)
at java.base@21.0.4/java.lang.reflect.Method.invoke(Method.java:580)
at java.base@21.0.4/java.util.ArrayList.forEach(ArrayList.java:1596)
at java.base@21.0.4/java.util.ArrayList.forEach(ArrayList.java:1596)
이번엔 가끔씩 나오는 문제인데 email unique가 문제가 생긴것을 볼 수 있다.
'z-google'이라니 email 랜덤값이z인거 같은데
최소길이를 정해줘야한다
public class TestDataBuilderGroup implements ArbitraryBuilderGroup {
@Override
public ArbitraryBuilderCandidateList generateCandidateList() {
return ArbitraryBuilderCandidateList.create()
.add(
ArbitraryBuilderCandidateFactory.of(Member.class)
.builder(
builder->builder
.setNull(javaGetter(Member::getId))
.set(javaGetter(Member::getName), Arbitraries.strings().ofMaxLength(50))
.set(javaGetter(Member::getEmail), Arbitraries.strings().alpha().ofMinLength(10).ofMaxLength(250))
.set(javaGetter(Member::getRole), MemberRole.ROLE_USER)
.set(javaGetter(Member::getProvider), "google")
.setNull(javaGetter(Member::getDeletedAt))
)
)
.add(
ArbitraryBuilderCandidateFactory.of(Note.class)
.builder(
builder->builder
.setNull(javaGetter(Note::getId))
.set(javaGetter(Note::getTitle), Arbitraries.strings().ofMaxLength(50))
.setNull(javaGetter(Note::getDeletedAt))
)
)
.add(
ArbitraryBuilderCandidateFactory.of(Deck.class)
.builder(
builder->builder
.setNull(javaGetter(Deck::getId))
.set(javaGetter(Deck::getName), Arbitraries.strings().ofMaxLength(50))
.set(javaGetter(Deck::getOriginalType), DeckOriginalType.ORIGINAL)
.set(javaGetter(Deck::getCardCounts), 0)
.setNull(javaGetter(Deck::getDeletedAt))
)
)
.add(
ArbitraryBuilderCandidateFactory.of(Card.class)
.builder(
builder->builder
.setNull(javaGetter(Card::getId))
.set(javaGetter(Card::getFront), Arbitraries.strings().ofMaxLength(50))
.set(javaGetter(Card::getBack), Arbitraries.strings().ofMaxLength(50))
.set(javaGetter(Card::getState), State.LEARNING)
.set(javaGetter(Card::getDue), Instant.now())
.set(javaGetter(Card::getLastReviewAt), Instant.now())
.set(javaGetter(Card::getFsrsData), "{}")
.setNull(javaGetter(Card::getDeletedAt))
)
)
;
}
public static FixtureMonkey fixtureMonkey(){
return FixtureMonkey.builder()
.objectIntrospector(BuilderArbitraryIntrospector.INSTANCE)
.plugin(new JakartaValidationPlugin())
.registerGroup(new TestDataBuilderGroup())
.build();
}
}
중요 entity마다 입력값을 미리 정하는 규칙을 정하고 테스트마다 재사용하도록 하면 문제를 해결할 수 있다.