728x90
반응형
728x90
반응형
반응형

maven3부터는 repository와의 통신을 https만 지원한다.

하지만 사내 repository는 http로만 통신이 되어야 하고 https일 경우 에러가 나는 상황이라 난감하였다.

이것 때문에 maven2를 사용했었는데 intellij 최신버전에서는 maven2를 사용할 수 없다.

 

intellij에 별도의 메이븐을 설정한다.

번들이 아닌 별도의 메이븐을 사용해야만 문제해결이 쉽다.

해당 경로에 가서 settings.xml을 열고 아래 부분을 주석처리 한다.

해결!

728x90
반응형
반응형

 

메이븐 pom.xml에서 자꾸 annotationProcessorPaths 에러가 난다.

다른 예시에서는 된다고 하는데 왜 나만 안 되는 것인지 의아했는데..

해결은 의외뢰 간단했다. 메시지가 그저 불편하게 나왔을 뿐.

<version>3.8.1</version>

해당 plugin 에 버전이 있는지 확인해 보고, 없을 경우 넣도록 하자!!!!!

728x90
반응형

'개발 > java' 카테고리의 다른 글

[map] getOrDefault vs computeIfAbsent  (0) 2023.12.20
[pom] http로 repository 연결  (0) 2023.10.23
[java] orElse vs orElseGet  (0) 2023.10.11
디자인 패턴  (0) 2023.07.11
[이슈해결] NPE at HSSFSheet.autoSizeColumn  (0) 2023.06.28
반응형

환경: springboot2.5+, mysql

 

일반적으로 테이블은 아래와 같이 camel case 사용한다.

그래서 spring에 아래의 설정을 적용하고 엔티티에 camel case로 콜롬을 받는다.

(springboot3 기준)

spring.jpa.properties.hibernate.physical_naming_strategy=org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy
spring.jpa.properties.hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy

(springboot2 기준)

spring.jpa.properties.hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
spring.jpa.properties.hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy

(entity)

@Id
private BigInteger idSeq;
private String configType;
private String configName;
private LocalDateTime startDate;
private LocalDateTime endDate;
private String data;
private Short active;
private String regAdmin;
private String modAdmin;
private LocalDateTime regDate;
private LocalDateTime modDate;

 

 

근데 진짜 간혹 가다 아래와 같이.. camel case가 든 테이블이 섞여있는 경우가 있다.

이 entity의 column은 어떻게 정의해야 할까?

그래서 제일 먼저 생각나는 @Column을 이용해 재정의를 해본다.

@Column(name = "startTimeMillis")
private BigInteger startTimeMillis;
@Column(name = "expiryTimeMillis")
private BigInteger expiryTimeMillis;
@Column(name = "autoRenewing")
private String autoRenewing;

하지만 physical 설정은 맨 마지막에 적용되기 때문에..

startTimeMillis로 가져오라고 명명한 콜롬 역시 start_time_millis로 디비를 조회하여 에러가 난다.

그럼 어떻게 하지? 이 몇 개의 테이블 때문에 위 hibernate strategy를 포기하자니,, 모든 콜롬명을 재정의할 자신이 없다..

(PhysicalNamingStrategyStandardImpl 로 사용해야 할 것 같은데 이러면 기존 자바 속성값을 다 @Column(name= 언더스코어네임)으로 지정해야 하는 불편함이 생긴다..)

 

해결

쿼리를 짤 때 대소문자 구분이 없다는 사실이 떠올랐다.

즉, rewardCount, rewardcount, REWARDCount 건 쿼리는 잘 실행된다.

디비의 camel case 또한 사람의 눈에는 camel case 지만 컴퓨터한테는 별 의미 없는 구분인 것이다.

그래서 아래와 같이 @Column을 명명하고 사람의 눈에는 보기 좋아야 하니까 변수명에는 camel case로 구분하였다.

@Column(name = "starttimemillis")
private BigInteger startTimeMillis;
@Column(name = "expirytimemillis")
private BigInteger expiryTimeMillis;
@Column(name = "autorenewing")
private String autoRenewing;

별문제 없이 쿼리가 실행되는 것 확인하였다.

728x90
반응형
반응형

apache 설정 중 virtual-host의 프록시 부분을 수정하였는데 304 NOT_MODIFIED 라는 문구와 함께 화면이 나오지 않았다.

나의 경우는 스웨거 페이지를 열려고 프록시에 아래처럼 /swagger-ui 를 추가한건데 스웨거 페이지가 열리지 않는 것이 아닌가..

  ...  
    ProxyPass /api http://localhost:6003/api
    ProxyPassReverse /api http://localhost:6003/api
    ProxyPass /swagger-ui http://localhost:6003/swagger-ui
    ProxyPassReverse /swagger-ui http://localhost:6003/swagger-ui
...

 

알고보니 스웨거 resource(이미지 등)을 불러오기 위해서 다른 url 호출이 있는데(/v3/api-docs/ 등) 이를 아파치 프록시에 설정하지 않아서 생기는 오류였다.

 

해결: 모든 resource path를 알기 어려워서 /로 bypass하도록 열어두었다(개발용 내부망이라 보안에 위배되지는 않는다. 만약 디테일하게 걸어야하면 관련 path 분석하여 넣어야 함).

728x90
반응형

'서버 세팅 & tool > nginx' 카테고리의 다른 글

[nginx + springboot] x-forwarded-for.. 진짜 client ip를 찾아서  (0) 2024.04.16
라이브환경 인증서 교체  (0) 2024.01.08
[nginx] WAF  (0) 2022.03.30
[nginx] API gateway  (0) 2022.03.14
[nginx] 실전 cors 해결하기  (0) 2022.03.14
반응형

환경: java 8+

java optional을 사용할 경우

null값을 대비해 기본 값을 return 할 수 있는 아래 두 함수가 있다.

orElse vs orElseGet

 

두 함수 모두 기본 값을 반환 할 수 있는데

orElse는 T객체 그 자체를, orElseGet은 람다식을 넘길 수 있다는 차이가 있다.

//orElse
UserStatistics one = statistics.stream().filter(UserStatistics::isHoldem).findFirst().orElse(new UserStatistics());
//orElseGet
UserStatistics one = statistics.stream().filter(UserStatistics::isHoldem).findFirst().orElseGet(() -> new UserStatistics());

 

또한 메모리/성능 상에서 차이도 있다.

orElse 는 값이 존재하여 else에 설정한 값을 반환하지 않게 될 때에도 이미 만들어 놓는다.

orElseGet은 값이 없어 진짜 필요할 때 실행된다.

 

따라서, 

constant, static variable, or caching result 을 반환할 경우라면 orElse를 사용해도 되지만, 대량 작업을 하거나 새로운 객체를 생성해야할 경우 orElseGet를 사용하는게 좋겠다.


참고

https://medium.com/@ductin.tran/use-java-optional-orelse-and-orelseget-wisely-4eebb50aa12e

 

Use Java Optional OrElse and OrElseGet wisely

1. Introduction

medium.com

 

728x90
반응형

'개발 > java' 카테고리의 다른 글

[pom] http로 repository 연결  (0) 2023.10.23
[pom] element annotationprocessorpaths is not allowed here  (0) 2023.10.23
디자인 패턴  (0) 2023.07.11
[이슈해결] NPE at HSSFSheet.autoSizeColumn  (0) 2023.06.28
[java] lambda stream and final  (0) 2023.02.06
반응형

환경: springboot2.5 이상, mysql 5.7 버전

 

1. spring jpa h2디비 적용 시 테이블 명이 아래와 같을 때 아무 설정을 안 해주면 camel case -> snake로 변형되어 적용된다.

@Table(name = "GlobalAccounts")

즉 위 테이블이 global_accounts 로 변경되어 생성된다.

테이블 명 그대로 적용되어야 한다면 아래 설정을 추가한다.

spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

 

2. 프로덕션 코드의 설정파일이 yml 이고 테스트 코드 설정파일이 properties 면 자동으로 설정되지 않는 것다. 도대체 왜지?!!!

https://mageddo.com/tools/yaml-converter 로 굳이 properties -> yml을 변환하여 설정하였다.

그게 싫다면 아래 어노태이션을 매 테스트 클래스마다 넣어야 하는데 매우 별로..

@TestPropertySource(locations = "classpath:application.properties")

 

+ application.properties 와 application.yml 둘 다 있을 경우 yml -> properties 순으로 로딩되어 같은 key값이 있을경우 properties의 값으로 덮어짐

 

3. rownum에 대하여

mysql 8.0 이상에서는 row_number() 윈도우 함수를 사용가능하나 그 이하 버전에서는 지원하지 않는다.

그래서 아래와 같이 session variable을 이용하여 쿼리 내에서 등수를 뽑곤 하는데..

여기서

1. session variable 명이 h2 예약어(rownum) 이면 identifier 에러가 나고

expected identifier [42001-200]

http://www.h2database.com/html/advanced.html

2. 다른 이름으로 바꿔도.. 제대로된 순위가 나오지 않는다..

 

h2에서 등수를 뽑거나,, session variable을 사용하려면 아래 h2함수를 사용해야 하는 것 같다..

http://h2database.com/html/functions.html#set

 

즉.. springboot jpql로 native query를 테스트하려면.. h2 문법도 잘 알아야할 듯하다.

 

4. String value too long 에러

h2의 경우 String에 어마무시한 json을 담을 경우 아래와 같은 에러를 만날 수 있는데,

Caused by: org.h2.jdbc.JdbcSQLDataException: Value too long for column "options CHARACTER VARYING(255)"

String은 기본 255 길이까지 가능이라, 그 이상의 데이터는 최장 길이를 아래와 같이 명시해주어야 한다..

@Column(length = 512)
private String options;
728x90
반응형
반응형

환경: spring jpa 2.5

Native Query 사용 시 `Space is not allowed after parameter prefix ':'`

라는 에러 발생

 

아래 쿼리의 @rownum := @rownum+1 에서 발생

:= 가 문제였음.

select * from 
(select seasonid, profileid, score, @rownum := @rownum+1 as ranking
from Season, (SELECT @rownum :=0)r

 

해결: \\를 추가하여 해결

@rownum \\:= @rownum+1

 

728x90
반응형
반응형

7. 경계조건

테스트 작성 시 경계 조건을 생각하는데 도움이 될 방법 CORRECT

 

7.1 Conformance 준수

특정 양식을 준수해야할 경우, N * M 가지의 경우의 수 고려

  • 이메일
  • 전화번호
  • 문서 등
헤더 데이터 트레일러
O O O
O O X
O X O
X O O
O X X
X O X
X X O
X X X
  • 처음 입력될 때 검증하면 매번 검증할 필요 없음
    • controller단이나 mapping될 때

 

7.2 ORDERING 순서

  • sorting
  • asc, desc 로 나열 시 맨 처음 값이 제일 큰지/작은지/최신순인지 등 확인 필요

 

7.3 RANGE 범위

경계 범위, 바깥 값 검증

  • int 인데 음수로 들어올 경우?
  • MAX + 1 이 들어올 경우?

primitive obsession(기본형의 과도한 사용)을 피하고 object로 만들어야 한다.

그리고 그 내부에서 검증로직과 경계값에 대한 조건을 가지고 있는게 좋다.

  • 예시: Bearing.java /  Rectangle.java : object안에서 범위에 대한 제약을 다룬다(넘는 경우 예외 포함).
  • RectangleTest.java : 공통 검증 로직을 @After 에서

cf. primitive obsession이란

  • 관련된 데이터를 묶지 못하고 흩어놓아 사용하는 것
  • 이 경우 각각의 데이터에 대한 정보를 외부에 공개하게 됨
  • 함수를 만들때도 각각의 데이터를 파라미터로 넘겨주어야 하기에 파라미터의 갯수가 늘어남
  • 이 때 관련된 데이터를 하나의 구조체(객체)로 묶어 사용해야한다.

https://medium.com/the-sixt-india-blog/primitive-obsession-code-smell-that-hurt-people-the-most-5cbdd70496e9

 

Primitive Obsession — code smell that hurt people the most

Most of the time, developers are aware of common code imperfections and most of the time know how to deal with them like long method…

medium.com

 

7.3.1 커스텀 매처 생성하는 법

hamcrest assertThat

public static <T> void assertThat(T actual, Matcher<? super T> matcher)

 TypeSafeMatcher를 상속받아서 매처 인스턴스를 반환하는 정적 팩토리 매서드(static @Factory method)를 제공하는 방식으로 커스텀 매쳐를 만들 수 있음(ConstrainsSidesTo.java, RectangleTest.java)

 

7.3.2 불변 함수를 내장하여 범위 테스트

sparseArray라는 자료구조를 직접 구현

  • 내부 배열에 저장된 값을 검증하는 테스트 코드를 작성할 때
  • 불필요하게 내부 구현 사항을 노출하기보다
  • 검증 함수를 만들어서 활용하는게 낫다(테스트 코드에서도 쓰고, 필요시 로직에서도 쓰고; checkInvariants())
    • 이 때 코드의 어느 부분에 문제가 있는지 더 쉽게 파악 가능

 

cf. sparseArray

0이 데이터보다 훨씬 많이 있는 array. 0을 실제 저장하지 않고 데이터가 있는 값만을 특별한 형식으로 저장하여 메모리를 효율적으로 사용하려는 방법을 취함.

A sparse array is an array of data in which many elements have a value of zero. This is in contrast to a dense array, where most of the elements have non-zero values or are “full” of numbers. A sparse array may be treated differently than a dense array in digital data handling.

https://developer88.tistory.com/entry/SparseArray-%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94

https://www.geeksforgeeks.org/what-is-meant-by-sparse-array/

 

What is meant by Sparse Array? - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

 

경계 대상이 인덱스일 경우 아래 사항 고려

  • 시작과 마지막 인덱스가 같으면 안됨
  • 시작이 마지막보다 크면 안됨
  • 인덱스는 음수가 아니어야 함
  • 인덱스가 허용된 값보다 크면 안됨
  • 갯수가 기대값과 같아야 함

 

7.4 Reference 참조

  • 외부 의존성이 있는지
    • 특정 상태에 있는 객체를 의존하는지
  • pre-condition(사전조건) / post-condition(사후조건; 코드가 참을 유지해야하는 조건; assertion; 메서드 반환 )이 있는지 확인
    • 가정이 맞을 때
    • 가정에 맞지 않을 때
      • side effect 확인

 

7.5 Existence 존재

  • null, 0, empty
  • 기대하는 파일이 없을 때
  • 네트워크 다운

 

7.6 Cardinality 기수 / 갯ㅅ

  • 0, 1, N(다수; 경계조건)
    • N은 비즈니스 요구사항에 따라 바뀔 수
  • 0 -> 1 -> N 에 관한 테스트코드

 

7.7 Time 시간

  • 상대적 시간(시간 순서)
    • 테스트 호출 순서 무관
    • 언제든지 반복가능한 테스트
  • 절대적 시간(측정된 시간)
    • 너무 오래걸리지 않는 테스트
    • timeout / 무한대기 고려
  • 동시성/동기화

 

728x90
반응형
반응형

5. 좋은 테스트의 조건 FIRST

5.1 FIRST

https://santim0ren0.medium.com/clean-code-unit-test-3e4b9ee63cb3

5.2 First: 빠르다

  • 테스트를 빠르게 유지해야 함
  • 하루에 서너번 실행하기도 버겁다면 잘못된 것
  • 지속적이고 종합적인, 빠른 피드백을 주지못하면 테스트의 가치가 떨어짐
  • 테스트가 느리다면, 디비와 같은 외부 의존성을 줄여라
    • 외부 의존성은 테스트를 느리게 할 뿐만 아니라 디비에서 값이 변하면 테스트 결과도 변할 것이기에 테스트 자가 불안해짐
    • 책의 예시
      • before: given절에서 테스트를 위한 데이터를 실 디비에서 가져옴
      • after:
        • 1. 디비 조회 결과를 받아서 함수에 주입해주는 방식으로(method argument) 테스트하고자하는 함수를 분리
        • 2. 테스트 코드에선 (디비 결과라고 가정된) 해시맵/리스트를 만들어 테스트
        • 3. 테스트가 빨라졌고 느린 것에 의존하는 코드도 최소화되어 더 나아졌다고 할 수 있음

 

5.3 Independent/Isolated: 고립시킨다

  • 단위테스트: 검증하려는 작은 양의 코드에 집중
  • 최소의 의존성
    • 테스트를 깨뜨리지 않는/ 느리게 하지 않는 / 가용성 / 접근성
  • 다른 단위 테스트에 의존하지 않도록
  • 순서나 시간에 관계없이 실행되어야
  • SRP: 테스트가 하나 이상의 이유로 깨진다면 테스트를 분할하라

 

5.4 Repeatable: 반복 가능해야한다

  • 실행할 때마다 같은 결과 보장
  • 직접 통제할 수 없는 외부 환경에 있는 항목들과 격리
  • 시간을 다뤄야 한다면? 
    • java8.time.Clock 객체를 주입받아(생성자나 setter로 생성시 주입) / 책의 예시

 

5.5 Self validating: 스스로 검증 가능하다

  • 테스트 결과를 수동으로(로그를 눈으로 읽는다거나)하는 방식은 시간이 많이 들고 리스크가 있음
    • -> 자동화 해야
  • CI(지속적 통합;저장소 감지하여 빌드와 테스트)/CD(지속적 배포;)

 

5.6 Timely: 적시에 하다

  • 단위 테스트를 언제 작성하는가?
    • 단위 테스트는 좋은 습관.
    • 절대 미루지말라. 한번 미루면 다시 테스트를 작성하기는 힘들어진다.
  • 팀 내 규칙을 세우라
    • ex. 테스트되지 않은 코드는 반영하지 않는다, CI 환경에 확인할 수 있도록 한다..
  • 옛날 코드에 대한 테스트는 시간 낭비가 될 수도
    • 코드에 큰 결함이 없고 당장 변경 예정이 없다면 그 노력을 신규 코드에

 

728x90
반응형
반응형

4. 테스트 조직

4.1 테스트 코드를 작성할 때 AAA

Arrange: 테스트 코드 실행 전 준비; 객체 생성

Act:테스트 코드 실행

Assert: 실행한 코드가 기대한 대로 동작하는지 확인

After: 때에 따라 필요; 테스트 실행 시 어떤 자원을 할당했다면 clean up 필

=> 각 구분을 구별하기 위해 빈 줄을 삽입

 

  1. Given/When/Then
    • Given
      • 테스트를 위해 주어진 상태
      • 테스트 대상에게 주어진 조건
      • 테스트가 동작하기 위해 주어진 환경
    • When
      • 테스트 대상에게 가해진 어떠한 상태
      • 테스트 대상에게 주어진 어떠한 조건
      • 테스트 대상의 상태를 변경시키기 위한 환경
    • Then
      • 앞선 과정의 결과

 

4.2 단위 테스트를 작성할 때는 먼저 전체적인 시각에서 시작해야

개별 메서트를 테스트하긴 하는 것이 아니라

  • 입금
  • 출금
  • 잔액확인

클래스의 종합적인 동작을 테스트 하는 관점에서 테스트를 작성해야함

  • 입금 -> 잔액 확인 -> 출금 -> 잔액 확인 등의 흐름으로 클래스 전체를 테스트

 

4.3 테스트와 프로덕션 코드의 관계

테스트 코드와 프로덕션 코드는 분리되어야

1. 테스트를 프로덕션 코드와 같은 디렉터리/패키지에 넣기

-> x; 테스트코드를 따로 분리하기 어려움

2. 테스트를 별도 디렉터리로 분리하지만 프로덕션 코드와 같은 패키지에 넣기

-> 주로 채택; test의 디렉터리 구조가 src 디렉터리를 반영; 테스트 클래스는 패키지 수준의 접근 권한을 가짐

3. 테스트를 별도의 디렉터리와 유사한 패키지에 유지

-> 테스트 코드를 프로덕션 코드의 패키지와 다르게하면 public 인터페이스만 활용하여 테스트코드 작성하게 되미. 많은 개발자가 의도적으로 설계할 때 이 정책을 채택

4.3.2 내부 데이터 노출 vs 내부 동작 노출

  • public method가 아닌 함수(비공개 코드; private method)를 호출하는 테스트는 구현 세부 사항과 결속이 심해져 테스트가 깨질 수 있음.
  • 내부의 세부 사항을 테스트하는 것은 저품질로 이어짐
    • ex. 코드의 작은 변화가 수많은 테스트를 깨면(과도하게 내부 구현 사항을 알고 있기에) -> 개발자는 당황 -> 테스트가 더 많이 깨질수록 개발자는 리팩토링이 꺼려짐 -> 코드의 퇴화
  • 테스트를 위해 내부 데이터를 노출하는 것은 테스트와 프로덕션 코드 사이에 과도한 결합을 초래
    • 테스트를 위해 getter 생성
  • private method를 테스트하고 싶은 충동이 든다면.. 설계에 문제가 있는 것(클래스의 SRP위배)
    • -> 의미있는 private method를 추출하여 별도의 클래스로 분리

 

4.4 집중적인 단일 목적 테스트의 가치

테스트는 주요 동작을 단위로 적당하게 나눠야

  • 테스트가 실패할 경우 실패한 테스트 이름이 표시되기에 어느 동작에 문제가 있는지 파악 가능
  • 실패한 테스트를 해독하는 시간을 줄일 수 있음
  • 테스트가 실패할 경우 테스트가 중지되기 때문에 모든 케이스가 실행됨을 보장가능

 

4.5 문서로서의 테스트

4.5.1 일관성 있는 이름으로 테스트를 문서화

  • 어떤 맥락에서 일련의 행동을 호출했을 어떤 결과가 나오는지 명시
  • 단어 일곱개를 넘어가면.. 너무 긴 이름
  • given-when-then 의 양식을 쓸수도
    • givenSomethingWhenDoingThisBehaviorThenSomeResultOccurs
    • 근데 너무 길다.. -> given절 생략
    • doingSomeOperationGeneratesSomeResult
  • 다른 사람에게 의미있게 만들기!

4.5.2 테스트를 의미있게 만들기

  • 테스트가 무슨 일을 하는지 바로 파악할 수 있도록 이름을 개선
  • 지역 변수 이름 개선
  • 의미있는 상수 도입
  • 햄크래스트 단언
  • 커다란 테스트를 나눠 집중적인 테스트 만들기
  • 공통 초기화/정리가 필요한 경우 @Before/@After 사용
  • 테스트 공통화

4.6 @Before/@After

  • @Before는 중복된 초기화가 있을 경우 공통화를 위해 사
    • @Before은 매번 테스트 메서드 실행에 앞서 실행됨
    • 초기화가 늘어갈 경우 @Before 메스드를 여러개로 분할
      • 이 경우 실행 순서를 보장하지 않음
      • 일정한 순서가 필요하다면 단일 @Before 메서드로 결합하여야 함
  • @After는 각 테스트를 한 후에 실행
    • 테스트가 실패하더라고 실행됨
    • 테스트에 발생하는 부산물을 정리

4.6.1 BeforeClass & AfterClass

@BeforeClass 모든 테스트 실행하기 전 한번만

@AfterClass 모든 테스트 실행 후 한번만

 

4.7 테스트를 의미있게 유지; 항상 통과하도록

4.7.1 단위 테스트는 빨라야 

  • 외부 자원에 접근 시 목객체 활용하여 빠르게
  • 필요하다고 생각하는 테스트만 실행
    • BUT 주기적으로 전체 테스트를 돌려 문제를 바로 찾을 수 있도록(묵히지 않도록)
    • 이게 힘들다면 변경되는 클래스 단위/함수 단위의 테스트라도 실행해서 테스트가 통과되도록 유지해야
    • -> 견딜 수 잇는 만큼 많은 테스트 실행하

4.7.2 테스트 제외

테스트 실패 시 주석처리말고 @Ignore 

테스트 돌리면 몇 개의 테스트가 skip 되었는지 알려

728x90
반응형

+ Recent posts