EventControllerTest에서 여러 Test가 깨집니다. 부탁드립다..ㅠㅠ
보면 여러 테스트가 깨지는데 에러 소스를 보았습니다.
모든 test의 에러는 같습니다.
인터넷에 찾아보니까 무결성 문제라고 하는데 Before로 모든 account를 deleteAll해놨습니다. 그리고 Account도 생성할때마다 generateId를 지정해놓은 상태입니다. 에러가 뜨는데 updateEvent할때 만든 Account를 before에서 삭제하고 다시 만들어서 사용할텐데 왜 이런 무결성문제가 뜨는지 잘 모르겠습니다.
먼저 선장님 강의를 보면서 처음에 account를 2개 만들고 테스트가 실행되면서 2개가 지워지고 updateEvent를 하면서 id = 3인 account가 생성되고 지워질텐데 에러에 id=4? 란게 있어서 잘 이해가 안됍니다. 도움 부탁드립니다.
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["FKPHLYW4Y37TCVEHS0E107B93CN: PUBLIC.EVENT FOREIGN KEY(MANAGER_ID) REFERENCES PUBLIC.ACCOUNT(ID) (4)"; SQL statement:
delete from account where id=? [23503-200]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:298)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:255)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:538)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:744)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:712)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:631)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:385)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:178)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy127.deleteAll(Unknown Source)
at com.hj.spring.events.EventControllerTest.setUp(EventControllerTest.java:58)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:40)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:80)
at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:71)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:137)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:200)
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:45)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3542)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3801)
at org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:100)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
at org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:478)
at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:348)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:40)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:108)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1344)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:435)
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3221)
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2389)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:447)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:183)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:40)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:281)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:534)
... 64 more
Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Referential integrity constraint violation: "FKPHLYW4Y37TCVEHS0E107B93CN: PUBLIC.EVENT FOREIGN KEY(MANAGER_ID) REFERENCES PUBLIC.ACCOUNT(ID) (4)"; SQL statement:
delete from account where id=? [23503-200]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:459)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:429)
at org.h2.message.DbException.get(DbException.java:205)
at org.h2.message.DbException.get(DbException.java:181)
at org.h2.constraint.ConstraintReferential.checkRow(ConstraintReferential.java:373)
at org.h2.constraint.ConstraintReferential.checkRowRefTable(ConstraintReferential.java:390)
at org.h2.constraint.ConstraintReferential.checkRow(ConstraintReferential.java:265)
at org.h2.table.Table.fireConstraints(Table.java:1057)
at org.h2.table.Table.fireAfterRow(Table.java:1075)
at org.h2.command.dml.Delete.update(Delete.java:153)
at org.h2.command.CommandContainer.update(CommandContainer.java:198)
at org.h2.command.Command.executeUpdate(Command.java:251)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:191)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:152)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
... 85 more
Answer 5
1
setUp() 메소드 안에서 데이터를 삭제할 때 Account를 삭제하기 전에 Event의 데이터 부터 삭제해야 합니다. Event가 Account 정보를 FK로 참조하고 있으니까요. setUp() 안에서 순서만 바꾸면 모든 테스트가 잘 동작할 겁니다.
0
package com.hj.spring.events;
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders;
import static org.springframework.restdocs.headers.HeaderDocumentation.responseHeaders;
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel;
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.relaxedResponseFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.time.LocalDateTime;
import java.util.Set;
import java.util.stream.IntStream;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.MediaTypes;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.security.oauth2.common.util.Jackson2JsonParser;
import org.springframework.test.web.servlet.ResultActions;
import com.hj.spring.accounts.Account;
import com.hj.spring.accounts.AccountRepository;
import com.hj.spring.accounts.AccountRole;
import com.hj.spring.accounts.AccountService;
import com.hj.spring.common.AppProperties;
import com.hj.spring.common.BaseControllerTest;
import com.hj.spring.common.TestDescription;
public class EventControllerTest extends BaseControllerTest{
@Autowired
private EventRepository eventRepository;
@Autowired
private AccountService accountService;
@Autowired
private AccountRepository accountRepository;
@Autowired
private AppProperties appProperties;
@Before
public void setUp() {
this.accountRepository.deleteAll();
this.eventRepository.deleteAll();
}
@Test
@TestDescription("정상적으로 이벤트를 생성하는 테스트")
public void createEvent() throws Exception {
EventDto eventDto = EventDto.builder()
.name("Srping")
.description("Spring API Development with Spring")
.beginEnrollmentDateTime(LocalDateTime.of(2020, 02, 19, 14, 19))
.closeEnrollmentDateTime(LocalDateTime.of(2020, 02, 20, 14, 19))
.beginEventDateTime(LocalDateTime.of(2020, 02, 21, 14, 19))
.endEventDateTime(LocalDateTime.of(2020, 02, 22, 14, 19))
.basePrice(100)
.maxPrice(200)
.limitOfEnrollment(100)
.location("Daejeon")
.build();
mockMvc.perform(post("/api/events/")
.header(HttpHeaders.AUTHORIZATION, getBearerToken(true))
.contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaTypes.HAL_JSON)
.content(objectMapper.writeValueAsString(eventDto))
)
.andDo(print())
.andExpect(status().isCreated())
.andExpect(jsonPath("id").exists())
.andExpect(header().exists(HttpHeaders.LOCATION))
.andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaTypes.HAL_JSON_VALUE))
.andExpect(jsonPath("free").value(false))
.andExpect(jsonPath("offline").value(true))
.andExpect(jsonPath("eventStatus").value(EventStatus.DRAFT.name()))
.andExpect(jsonPath("_links.self").exists())
.andExpect(jsonPath("_links.query-events").exists())
.andExpect(jsonPath("_links.update-event").exists())
.andDo(document("create-event",
links(
linkWithRel("self").description("link to self"),
linkWithRel("query-events").description("link to query-events"),
linkWithRel("update-event").description("link to update an existing"),
linkWithRel("profile").description("link to profile")
),
requestHeaders(
headerWithName(HttpHeaders.ACCEPT).description("accept header"),
headerWithName(HttpHeaders.CONTENT_TYPE).description("content type header")
),
requestFields(
fieldWithPath("name").description("Name of new event"),
fieldWithPath("description").description("Description of new event"),
fieldWithPath("beginEnrollmentDateTime").description("BeginEnrollmentDateTime of new event"),
fieldWithPath("closeEnrollmentDateTime").description("CloseEnrollmentDateTime of new event"),
fieldWithPath("beginEventDateTime").description("BeginEventDateTime of new event"),
fieldWithPath("endEventDateTime").description("EndEventDateTime of new event"),
fieldWithPath("location").description("Location of new event"),
fieldWithPath("basePrice").description("BasePrice of new event"),
fieldWithPath("maxPrice").description("MaxPrice of new event"),
fieldWithPath("limitOfEnrollment").description("LimitOfEnrollment of new event")
),
responseHeaders(
headerWithName(HttpHeaders.LOCATION).description("location header"),
headerWithName(HttpHeaders.CONTENT_TYPE).description("content type header")
),
//requestFields를 사용하면 links가 걸린다. 문서화하지 않았기 때문이다. 하지만 relaxed를 사용하면 모든것을 문서화하지 않아도됀다.
//단점은 정확한 문서를 만들지 못한다는거다.
//api가 바꼇을때 모든것을 다 하지않으면 api문서화가 제대로 되지 않는다.
relaxedResponseFields(
fieldWithPath("id").description("Id of new event"),
fieldWithPath("name").description("Name of new event"),
fieldWithPath("description").description("Description of new event"),
fieldWithPath("beginEnrollmentDateTime").description("BeginEnrollmentDateTime of new event"),
fieldWithPath("closeEnrollmentDateTime").description("CloseEnrollmentDateTime of new event"),
fieldWithPath("beginEventDateTime").description("BeginEventDateTime of new event"),
fieldWithPath("endEventDateTime").description("EndEventDateTime of new event"),
fieldWithPath("location").description("Location of new event"),
fieldWithPath("basePrice").description("BasePrice of new event"),
fieldWithPath("maxPrice").description("MaxPrice of new event"),
fieldWithPath("limitOfEnrollment").description("LimitOfEnrollment of new event"),
fieldWithPath("free").description("Free of new event"),
fieldWithPath("offline").description("Offline of new event"),
fieldWithPath("eventStatus").description("EventStatus of new event"),
fieldWithPath("_links.self.href").description("link to self"),
fieldWithPath("_links.query-events.href").description("link to query-event list"),
fieldWithPath("_links.update-event.href").description("link to update existing event"),
fieldWithPath("_links.profile.href").description("link to profile")
)
))
;
}
@Test
@TestDescription("입력 받을 수 없는 값을 사용한 경우에 에러가 발생하는 테스트")
public void createEvent_Bad_Request_Unknown_Input() throws Exception {
Event event = Event.builder()
.id(100)
.name("Srping")
.description("REST API Development with Spring")
.beginEnrollmentDateTime(LocalDateTime.of(2020, 02, 19, 14, 19))
.closeEnrollmentDateTime(LocalDateTime.of(2020, 02, 20, 14, 19))
.beginEventDateTime(LocalDateTime.of(2020, 02, 21, 14, 19))
.endEventDateTime(LocalDateTime.of(2020, 02, 22, 14, 19))
.basePrice(100)
.maxPrice(200)
.limitOfEnrollment(100)
.location("대전 현지의 러브하우스")
.eventStatus(EventStatus.PUBLISHED)
.free(true)
.offline(false)
.build();
mockMvc.perform(post("/api/events/")
.header(HttpHeaders.AUTHORIZATION, getBearerToken(true))
.contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaTypes.HAL_JSON)
.content(objectMapper.writeValueAsString(event))
)
.andDo(print())
.andExpect(status().isBadRequest())
;
}
@Test
@TestDescription("입력값이 비어있는 경우에 에러가 발생하는 테스트")
public void createEvent_Bad_Request_Empty_Input() throws Exception {
EventDto eventDto = EventDto.builder().build();
mockMvc.perform(post("/api/events/")
.header(HttpHeaders.AUTHORIZATION, getBearerToken(true))
.contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaTypes.HAL_JSON)
.content(objectMapper.writeValueAsString(eventDto))
)
.andExpect(status().isBadRequest())
.andDo(print())
.andExpect(jsonPath("_links.index").exists())
;
}
@Test
@TestDescription("입력 값이 잘못된 경우에 에러가 발생하는 테스트")
public void createEvent_Bad_Request_Wrong_Input() throws Exception {
EventDto eventDto = EventDto.builder()
.name("Srping")
.description("REST API Development with Spring")
.beginEnrollmentDateTime(LocalDateTime.of(2020, 02, 22, 14, 19))
.closeEnrollmentDateTime(LocalDateTime.of(2020, 02, 21, 14, 19))
.beginEventDateTime(LocalDateTime.of(2020, 02, 20, 14, 19))
.endEventDateTime(LocalDateTime.of(2020, 02, 19, 14, 19))
.basePrice(10000)
.maxPrice(200)
.limitOfEnrollment(100)
.location("대전 현지의 러브하우스")
.build();
mockMvc.perform(post("/api/events/")
.header(HttpHeaders.AUTHORIZATION, getBearerToken(true))
.contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaTypes.HAL_JSON)
.content(objectMapper.writeValueAsString(eventDto))
)
.andDo(print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("content.[0].objectName").exists())
.andExpect(jsonPath("content.[0].defaultMessage").exists())
.andExpect(jsonPath("content.[0].code").exists())
.andExpect(jsonPath("_links.index").exists())
;
}
@Test
@TestDescription("30개의 이벤트를 10개씩 조회하는데 11~20 조회하기")
public void queryEvent() throws Exception{
// Given
IntStream.range(1, 31).forEach(i -> {
this.generatedEvent(i);
});
this.mockMvc.perform(get("/api/events/")
.param("page", "1")
.param("size", "10")
.param("sort", "id,DESC")
)
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("page").exists())
.andExpect(jsonPath("_embedded.eventList[0]._links.self").exists())
.andExpect(jsonPath("_links.self").exists())
.andExpect(jsonPath("_links.profile").exists())
.andDo(document("query-events"))
;
}
@Test
@TestDescription("30개의 이벤트를 10개씩 조회하는데 11~20 조회하기 With Authentication")
public void queryEventWithAuthentication() throws Exception{
// Given
IntStream.range(1, 31).forEach(i -> {
this.generatedEvent(i);
});
this.mockMvc.perform(get("/api/events/")
.header(HttpHeaders.AUTHORIZATION, getBearerToken(true))
.param("page", "1")
.param("size", "10")
.param("sort", "id,DESC")
)
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("page").exists())
.andExpect(jsonPath("_embedded.eventList[0]._links.self").exists())
.andExpect(jsonPath("_links.self").exists())
.andExpect(jsonPath("_links.profile").exists())
.andExpect(jsonPath("_links.create-event").exists())
.andDo(document("query-events"))
;
}
@Test
@TestDescription("기존의 이벤트 하나 조회하기")
public void getEvent() throws Exception {
// Given
Account account = this.createAccount();
Event event = this.generatedEvent(100, account);
// When
this.mockMvc.perform(get("/api/events/"+event.getId()))
.andExpect(status().isOk())
.andDo(print())
.andExpect(jsonPath("id").exists())
.andExpect(jsonPath("name").exists())
.andExpect(jsonPath("_links.self").exists())
.andExpect(jsonPath("_links.profile").exists())
.andDo(document("get-an-event"))
;
}
@Test
@TestDescription("없는 이벤트를 조회했을때 404응답받기")
public void getEvent404() throws Exception {
// When
this.mockMvc.perform(get("/api/events/123"))
.andExpect(status().isNotFound())
;
}
@Test
@TestDescription("이벤트를 정상적으로 수정하기")
public void updateEvent() throws Exception {
// Given
Account account = createAccount();
Event event = this.generatedEvent(200, account);
EventDto eventDto = modelMapper.map(event, EventDto.class);
String eventName = "Update event";
eventDto.setName(eventName);
// When
this.mockMvc.perform(put("/api/events/{id}",event.getId())
.header(HttpHeaders.AUTHORIZATION, getBearerToken(false))
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(objectMapper.writeValueAsString(eventDto))
.accept(MediaTypes.HAL_JSON)
)
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("name").value(eventName))
.andExpect(jsonPath("_links.self").exists())
.andDo(document("update-event"))
;
}
@Test
@TestDescription("입력값이 비어있는 경우 이벤트 수정 실패")
public void updateEvent_400_Empty() throws Exception {
//Given
Event event = this.generatedEvent(200);
EventDto eventDto = new EventDto();
this.mockMvc.perform(put("/api/events/{id}",event.getId())
.header(HttpHeaders.AUTHORIZATION, getBearerToken(true))
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(objectMapper.writeValueAsString(eventDto))
.accept(MediaTypes.HAL_JSON)
)
.andDo(print())
.andExpect(status().isBadRequest())
;
}
@Test
@TestDescription("입력값이 잘못된 경우 이벤트 수정 실패")
public void updateEvent_400_Wrong() throws Exception {
//Given
Event event = this.generatedEvent(200);
EventDto eventDto = modelMapper.map(event, EventDto.class);
eventDto.setBasePrice(20000);
eventDto.setMaxPrice(10000);
this.mockMvc.perform(put("/api/events/{id}",event.getId())
.header(HttpHeaders.AUTHORIZATION, getBearerToken(true))
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(objectMapper.writeValueAsString(eventDto))
.accept(MediaTypes.HAL_JSON)
)
.andDo(print())
.andExpect(status().isBadRequest())
;
}
@Test
@TestDescription("존재하지 않는 이벤트 수정")
public void updateEvent_404() throws Exception {
//Given
Event event = this.generatedEvent(200);
EventDto eventDto = modelMapper.map(event, EventDto.class);
this.mockMvc.perform(put("/api/events/12341234")
.header(HttpHeaders.AUTHORIZATION, getBearerToken(true))
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(objectMapper.writeValueAsString(eventDto))
.accept(MediaTypes.HAL_JSON)
)
.andDo(print())
.andExpect(status().isNotFound())
;
}
private Event generatedEvent(int i, Account account) {
Event event = BuildEvent(i);
event.setManager(account);
return this.eventRepository.save(event);
}
private Event generatedEvent(int i) {
Event event = BuildEvent(i);
return this.eventRepository.save(event);
}
private Event BuildEvent(int i) {
Event event = Event.builder()
.name("Srping")
.description("Spring API Development with Spring")
.beginEnrollmentDateTime(LocalDateTime.of(2020, 02, 19, 14, 19))
.closeEnrollmentDateTime(LocalDateTime.of(2020, 02, 20, 14, 19))
.beginEventDateTime(LocalDateTime.of(2020, 02, 21, 14, 19))
.endEventDateTime(LocalDateTime.of(2020, 02, 22, 14, 19))
.basePrice(100)
.maxPrice(200)
.limitOfEnrollment(100)
.location("Daejeon")
.free(false)
.offline(true)
.eventStatus(EventStatus.DRAFT)
.build();
return event;
}
private String getBearerToken(boolean needToCreateAccount) throws Exception {
return "Bearer " + getAcessToken(needToCreateAccount);
}
private Account createAccount() {
Account khj = Account.builder()
.email(appProperties.getAdminUsername())
.password(appProperties.getAdminPassword())
.roles(Set.of(AccountRole.ADMIN, AccountRole.USER))
.build();
return this.accountService.saveAccount(khj);
}
private String getAcessToken(boolean needToCreateAccount) throws Exception {
if(needToCreateAccount) {
createAccount();
}
ResultActions perform = this.mockMvc.perform(post("/oauth/token")
.with(httpBasic(appProperties.getClientId(), appProperties.getClientSecret()))
.param("username", appProperties.getAdminUsername())
.param("password", appProperties.getAdminPassword())
.param("grant_type", "password")
)
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("access_token").exists())
;
var responseBody = perform.andReturn().getResponse().getContentAsString();
Jackson2JsonParser parser = new Jackson2JsonParser();
return parser.parseMap(responseBody).get("access_token").toString();
}
}
Spring 시큐리티 관련해서 WebSecurityConfigurationAdapter
0
73
1
junit5 사용하시는 분들
0
88
1
자바 빈 스펙을 준수하는지 체크하는 테스트
0
237
2
REST API 개발 중 비즈니스 로직 적용 부분의 JSON 에러
0
243
1
스프링 부트 3버전에서의 실습
0
190
1
java.lang.AssertionError: Status
0
532
2
spring doc 관련 파일 생성 관련 배포 관련 질문 드립니다.
0
287
1
섹션2 201응답받기 부분 테스트 404에러 질문입니다
0
741
1
강의 자료가 404입니다 확인 부탁 드려요!
0
477
1
연동 DB문의
0
358
1
이벤트 Repository강의 중 Event 클래스에 private Integer Id; 위치 질문
0
505
1
(Mac) postgressql 관련하여 port kill 해도 다시 살아나는 경우
0
380
0
maven으로 생성한 docs파일(index.html)에서의 not found 오류 질문
0
621
1
테스트 오류 질문드립니다.
0
512
1
docs 요청값이 반영이 안되네요... (해결)
-1
394
1
psql 적용 후 에러
0
818
2
mvn package 시 다음과 같은 에러가 나시면
0
765
2
Event에 Account manager를 추가했으면 문서화 필요
0
274
1
2년 훨씬 전 부터 Restlet-> Talend API 로 바뀌었습니다~
1
473
1
asciidoc 추가 스니펫 에러 해결법
0
400
1
_links 는 현재 fieldWithPath 를 해주지 않아도 됩니다.
0
424
3
깃랩 처음 사용자를 위한 index.adoc raw 보는 법
0
332
1
eclipse 쓰시는 분을 위한 maven-resources-plugin 팁
0
333
1
부트 + jupiter 인 경우 설정법
0
342
1

