package com.daonstar.web;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;



public class ListToMapTest {
	
	private List<Book> books;
	private final String NAME = "책읽자";
	private final int RELEASE_YEAR = 2009;
	private final String ISBN = "0101234929";
	private final int initAddBookCount = 3;
	
	@Before
	public void init() {
		System.out.println("@Before");
		books = new ArrayList<>();
		booksAdds();
	}
	
	@After
    public void tearDown() throws Exception {
		System.out.println("@After");
		books.clear();
    }

	private void booksAdds() {
		for (int i = 0; i < initAddBookCount; i++) {
			
			int releaseYear = RELEASE_YEAR;
			if ( i > 1 ) {
				releaseYear = RELEASE_YEAR + i;
			}
			books.add(new Book(NAME + i, releaseYear, ISBN + i));
		}
	}
	
	private Map<String, String> listToMap(List<Book> books) {
		return books.stream().collect(Collectors.toMap(Book::getIsbn,  Book::getName));
	}

	@Test
	public void whenConvertFromListToMap() {
		System.out.println("@test1");
		assertTrue(listToMap(books).size() ==3);
	}
	
	public Map<Integer, Book> listToMapWithDupKeyError(List<Book> books) {
		return this.books.stream().collect(Collectors.toMap(Book::getReleaseYear,  Function.identity()));
	}
	
	
	@Test(expected = IllegalStateException.class)
	public void whenMapHasDuplicateKey_whthout_merge_function_then_runtime_exception() {
		listToMapWithDupKeyError(books);
	}
	
	public Map<Integer, Book> listToMapWithDupKey(List<Book> books) {
		return books.stream().collect(Collectors.toMap(Book::getReleaseYear,  Function.identity(), (existing, replacement) -> existing));
	}
	
	@Test
	public void whenMapHasDuplicateKeyThenMergeFunctionHandlesCollision() {
		Map<Integer, Book> booksByYear = listToMapWithDupKey(books);
		assertEquals(2, booksByYear.size());
		assertEquals(ISBN + 0, booksByYear.get(RELEASE_YEAR).getIsbn());
	}
	
	public Map<Integer, Book> listToConcurrentMap(List<Book> books) {
		return books.stream().collect(Collectors.toMap(Book::getReleaseYear,  Function.identity(), (o1, o2) -> o1, ConcurrentHashMap::new));
	}
	
	@Test
	public void whenCreateConcurrentHashMap() {
		assertTrue(listToConcurrentMap(books) instanceof ConcurrentHashMap);
	}
	
	
	public TreeMap<String, Book> listToSortedMap(List<Book> books) {
		return books.stream()
				.sorted(Comparator.comparing(Book::getName))
				.collect(Collectors.toMap(Book::getName, Function.identity(), (o1, o2) -> o1, TreeMap::new));
	}
	
	@Test
	public void whenMapisSorted() {
		String firstBookName = "책읽자0";
		assertTrue(listToSortedMap(books).firstEntry().getKey().equals(firstBookName));
	}
	
	
}

 

나름 TDD하면서 해봤다.

아직  JUnit도 어설퍼서 이것저것 태스트 하느라 로그도 찍었다.

Collectors.toMap 요놈 이용해서 리스트를 맵으로 바꾸면 되는 요지인데, 키 중복일때 처리 방법도 있다.

요지는 list to map 인데 테스트 관련해서 리팩토링 할려고 노력중이라 코드가 산으로 가고 다른 생각이 많이 든다.

 

참고 https://www.baeldung.com/java-collectors-tomap

 

Java 8 Collectors toMap | Baeldung

Learn how to use the toMap() method of the Collectors class.

www.baeldung.com

 

DataJpaTest를 연습중이다.

아래와 같이 진행하면 testRepository.save() 하면 실제로 쿼리를 실행시키지 않는다.

기본으론 내장 메모리로 하는 것 같다.

@RunWith(SpringRunner.class)
@DataJpaTest 

아래와 같이 추가해주면 쿼리가 실행되며 쿼리가 찍히는걸 확인 할수 있다.

@Transactional(propagation = Propagation.NOT_SUPPORTED)

 

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html

 

46. Testing

A Spring Boot application is a Spring ApplicationContext, so nothing very special has to be done to test it beyond what you would normally do with a vanilla Spring context. By default, @SpringBootTest will not start a server. You can use the webEnvironment

docs.spring.io

찾아보니 기본적으로 data JPA 테스트는 트렌잭션과 롤백이 된다고 하고,

위에 설정을 통해 트랜젝션 비활성으로 설정이 된다고 나와 있다.

 

데이터가 영속성에 잘 들어갔는지 실제로 Assert로 데이터를 가져와서 확인을 할려면

EntityManager를 사용해서 확인하는데

@Transctional을 사용하면

@TestEntityManager는 접근이 안되고 @EntityManager로 접근해야한다.

 

가상 서버에 도커로 mariadb설치후 기본으로 db 생성 하고 테스트 진행 했더니 아래와 같이 insert가 실패된다.

DataJpaTest로 실행 시켜선지 기본 Console 에는 자세하고 안나오고 Failure Trace에 자세히 보면 알수 있다.

결국은 DB 언어셋을 잘 맞춰주면 된다.

-----------------------------------------------------------------------------------------------------

could not execute statement; SQL [n/a]; nested exception is org.hibernate.exception.DataException: could not execute statement

at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:300)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:253)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:536)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:746)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:534)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:305)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
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:138)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy103.save(Unknown Source)
at com.daonstar.web.apps.board.BoardRepositoryTest.insert_단건_성공(BoardRepositoryTest.java:68)
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:567)
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.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
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.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.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:541)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
Caused by: org.hibernate.exception.DataException: could not execute statement
at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:52)
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:178)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3176)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3690)
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:90)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1454)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:511)
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3290)
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2486)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:473)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:178)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:39)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:271)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:104)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:532)
... 48 more
Caused by: java.sql.SQLDataException: (conn=210) Incorrect string value: '\xEA\xB2\x8C\xEC\x8B\x9C...' for column `board`.`board`.`name` at row 1
at org.mariadb.jdbc.internal.util.exceptions.ExceptionMapper.get(ExceptionMapper.java:225)
at org.mariadb.jdbc.internal.util.exceptions.ExceptionMapper.getException(ExceptionMapper.java:165)
at org.mariadb.jdbc.MariaDbStatement.executeExceptionEpilogue(MariaDbStatement.java:238)
at org.mariadb.jdbc.MariaDbPreparedStatementClient.executeInternal(MariaDbPreparedStatementClient.java:232)
at org.mariadb.jdbc.MariaDbPreparedStatementClient.execute(MariaDbPreparedStatementClient.java:159)
at org.mariadb.jdbc.MariaDbPreparedStatementClient.executeUpdate(MariaDbPreparedStatementClient.java:194)
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:175)
... 65 more
Caused by: java.sql.SQLException: Incorrect string value: '\xEA\xB2\x8C\xEC\x8B\x9C...' for column `board`.`board`.`name` at row 1
Query is: insert into board (created_date, editer_use_at, file_maximum_count, name, secret_use_type, update_date, id) values (?, ?, ?, ?, ?, ?, ?), parameters ['2019-06-07 10:00:07.6137353',0,2,'게시판이름','DISABLE','2019-06-07 10:00:07.6137353',16]
java thread: main
at org.mariadb.jdbc.internal.util.LogQueryTool.exceptionWithQuery(LogQueryTool.java:163)
at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.executeQuery(AbstractQueryProtocol.java:280)
at org.mariadb.jdbc.MariaDbPreparedStatementClient.executeInternal(MariaDbPreparedStatementClient.java:223)
... 70 more

+ Recent posts