전체 글 (356)

💻 Programming

Spock Test Framework 실행 오류 해결

(SpringBoot3 + Correto 17 (java 17) 환경에서 spock test 시 발생한

TestEngine with ID 'spock' failed to discover tests 오류 해결방안 공유합니다.

 

IntelliJ 에서 Spring Initializer를 이용하여

스프링부트3 + 자바 17 기반의 신규 프로젝트를 생성,

빌드가 정상적으로 되는지 확인 후

spock 테스트를 위한 라이브러리를 아래 3개 추가했습니다.

testImplementation 'org.spockframework:spock-core:2.4-M1-groovy-4.0'
testImplementation 'org.spockframework:spock-spring:2.4-M1-groovy-4.0'
testImplementation 'org.apache.groovy:groovy-all:4.0.13'

 

 

그리고 샘플 테스트 클래스를 만들었습니다.

class SampleSpec extends Specification {

    def "where with variables: #size"() {
        when:
        def list = new ArrayList(size)

        then:
        list.size() == 0

        where:
        size << [1, 2, 3, 4, 5]
    }

    def "using data tables for calculating max, Max of #a and #b is #max"() {
        expect:
        Math.max(a, b) == max

        where:
        a | b || max
        1 | 2 || 2
        7 | 4 || 7
        0 | 0 || 0
    }
}

 

 

실행을 해보았더니 아래와 같은 에러가 발생했습니다.

Internal Error occurred.
org.junit.platform.commons.JUnitException: TestEngine with ID 'spock' failed to discover tests
...중략...

Caused by: org.junit.platform.commons.JUnitException: ClassSelector [className = 'com.project.SampleSpec', classLoader = null] resolution failed
...중략...

Caused by: org.junit.platform.commons.PreconditionViolationException: Could not load class with name: com.project.SampleSpec
...중략...

Caused by: java.lang.ClassNotFoundException: com.project.SampleSpec

 

 

구글링 결과 build.gradle 파일의 plugins 에 id 'groovy' 를 추가해주면 되는 문제였습니다.

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.2.1'
    id 'io.spring.dependency-management' version '1.1.4'

    id 'groovy'  <-- 이게 있는지 확인
}

 

최근 2년정도 IntelliJ에서 Java 11 기반의 AWS Correto 11 을 사용해왔습니다

그래서 현재 JAVA_HOME 은 AWS Correto 11 의 위치를 가리키고 있었습니다.

신규 프로젝트 구성할 일이 생겼고

AWS Correto 17 을 미리 다운받아둔 상태에서

IntelliJ 에서 SpringBoot Initializer 를 이용해서

아래와 같은 설정(Java 17 + gradle groovy)으로 프로젝트를 생성하고

빌드를 하니 오류가 발생했습니다.

스프링부트 신규 프로젝트 생성 설정화면 (Java 17 설정)

 

아래는 빌드시 발생했던 오류 메시지

A problem occurred configuring root project 'my-new-springboot3-project'.
> Could not resolve all files for configuration ':classpath'.
   > Could not resolve org.springframework.boot:spring-boot-gradle-plugin:3.2.1.
     Required by:
         project : > org.springframework.boot:org.springframework.boot.gradle.plugin:3.2.1
      > No matching variant of org.springframework.boot:spring-boot-gradle-plugin:3.2.1 was found. The consumer was configured to find a library for use during runtime, compatible with Java 11, packaged as a jar, and its dependencies declared externally, as well as attribute 'org.gradle.plugin.api-version' with value '8.5' but:
          - Variant 'apiElements' capability org.springframework.boot:spring-boot-gradle-plugin:3.2.1 declares a library, packaged as a jar, and its dependencies declared externally:
              - Incompatible because this component declares a component for use during compile-time, compatible with Java 17 and the consumer needed a component for use during runtime, compatible with Java 11
              - Other compatible attribute:
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')
          - Variant 'javadocElements' capability org.springframework.boot:spring-boot-gradle-plugin:3.2.1 declares a component for use during runtime, and its dependencies declared externally:
              - Incompatible because this component declares documentation and the consumer needed a library
              - Other compatible attributes:
                  - Doesn't say anything about its target Java version (required compatibility with Java 11)
                  - Doesn't say anything about its elements (required them packaged as a jar)
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')
          - Variant 'mavenOptionalApiElements' capability org.springframework.boot:spring-boot-gradle-plugin-maven-optional:3.2.1 declares a library, packaged as a jar, and its dependencies declared externally:
              - Incompatible because this component declares a component for use during compile-time, compatible with Java 17 and the consumer needed a component for use during runtime, compatible with Java 11
              - Other compatible attribute:
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')
          - Variant 'mavenOptionalRuntimeElements' capability org.springframework.boot:spring-boot-gradle-plugin-maven-optional:3.2.1 declares a library for use during runtime, packaged as a jar, and its dependencies declared externally:
              - Incompatible because this component declares a component, compatible with Java 17 and the consumer needed a component, compatible with Java 11
              - Other compatible attribute:
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')
          - Variant 'runtimeElements' capability org.springframework.boot:spring-boot-gradle-plugin:3.2.1 declares a library for use during runtime, packaged as a jar, and its dependencies declared externally:
              - Incompatible because this component declares a component, compatible with Java 17 and the consumer needed a component, compatible with Java 11
              - Other compatible attribute:
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')
          - Variant 'sourcesElements' capability org.springframework.boot:spring-boot-gradle-plugin:3.2.1 declares a component for use during runtime, and its dependencies declared externally:
              - Incompatible because this component declares documentation and the consumer needed a library
              - Other compatible attributes:
                  - Doesn't say anything about its target Java version (required compatibility with Java 11)
                  - Doesn't say anything about its elements (required them packaged as a jar)
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.
BUILD FAILED in 1s

 

에러 메시지의 내용을 읽어보니, 일단 Could not resolve xxx 의 경우 xxx 라이브러리가 없다라는 메시지인데

신규 생성한 프로젝트에서 필수라이브러리를 dependency에 안넣을 이유가 없다는 생각이 우선 들었습니다.

그런거라면 springboot initializer 의 버그일테니까요.

그래서 더 읽어봤습니다.

그리고 "requierd compatibility with Java 11" 문구가 눈에 띄었습니다.

난 자바17을 쓰려고 17버전으로 JDK와 Java 설정을 넣었는데 왜 Java 11 관련메시지가 뜨는건지 이상했습니다. 🤔

에러메시지 내용으로 구글링을 좀 해보니 아래 부분들을 확인해보라는 내용들이 있었습니다.

  • 현재 시스템에서 사용하는 Java 버전 확인 (java -version)
  • build.gradle 파일의  sourceCompatibility 확인
  • IntelliJ 의 project SDK 설정 확인
  • gradle JVM 설정 확인

일단 빌드시에 발생했고, 빌드툴은 gradle 이라는 걸 이미 프로젝트 생성시 설정을 해주었고, IntelliJ에 gradle 이 사용할 자바버전을 설정하는 내용이 있다는 것을 알고있었기에 gradle JVM 설정을 먼저 확인해봤습니다.

gradle JVM 설정이 기존 설정 그대로 Java 11을 사용하도록 되어있었습니다. 😭

프로젝트 생성시 correto 17, Java 17 버전을 설정해주었기에 sourceCompatibility 와 project SDK 는 17버전을 사용하도록 되어있었고, JAVA_HOME에 설정되어있는 현재 시스템에서 기본으로 사용중인 Java 버전과는 관계가 없었습니다.

 

gradle JVM 설정 확인 방법

Preferences/Settings (⌘ + , ) > Build, Execution, Deployment > Build Tools > Gradle

Gradle JVM 설정 화면

project SDK 설정 확인 방법

File > Project Structure.. (⌘ + ; )

Project SDK 설정 화면

build.gradle 파일의 sourceCompatibility 확인 방법

build.gradle 파일에서 sourceCompatibility 설정 방법

💻 Programming

SpringBoot 2.3 -> 2.5 업그레이드 후기

SpringBoot 버전을 업그레이드 해야할 일이 생겨서 2.3 버전을 2.5 버전으로 업그레이드한 경험담을 공유합니다.

개발인생 처음으로 해보는 레거시 시스템의 프레임워크 업그레이드 작업이었습니다.

대부분은 신규 프로젝트를 만들거나 deprecate 된 상태로 유지하는 정도였죠.

그래도 해보고 싶었던 부분이었습니다. 업무가 많이 지루해진것도 한 몫 했죠.

저는 주기적으로 반기에 한번정도는 라이브러리 업그레이드 작업을 진행해야한다고 생각하지만

저희 개발팀은 이상하게 라이브러리 업그레이드 작업을 안합니다. 

그런데 갑자기 프레임워크 업그레이드를 하려니 dependency 가 많이 걸려있을거라 예상했죠.

 

우선 2.3 -> 2.4 로 올라가면서 어떤 부분에 변화가 생겼는지를 확인하고 대응하고,

2.4 -> 2.5 에서는 어떤 변화가 있었는지 확인하여 대응하면 될거라 생각했고 

아래 2개의 spring boot release note 를 하나하나 살펴봤습니다.

2.3 -> 2.4 에서 변경된 부분

  • JUnit 5’s Vintage Engine Removed from spring-boot-starter-test
  • Config File Processing (application properties and YAML files)
  • Config Data Imports
  • Embedded database detection
  • User-defined MongoClientSettings no longer customized
  • Logback Configuration Properties
  • Default Servlet Registration
  • HTTP traces no longer include cookie headers by default
  • Undertow Path on Forward
  • Neo4j
  • Hazelcast 4
  • Elasticsearch RestClient
  • R2DBC
  • Flyway
  • Removal of Plugin Management for Flatten Maven Plugin
  • Version management for exec-maven-plugin
  • Spring Boot Gradle Plugin
  • Metrics export in integration tests
  • Deprecations from Spring Boot 2.2 and 2.3

2.4 -> 2.5 에서 변경된 부분

  • SQL Script DataSource Initialization
  • Flyway and Liquibase JDBC URLs
  • Spring Data JPA
  • Spring Data Solr
  • Secure Info Endpoint
  • Task Scheduling Harmonization with Spring Integration
  • Default Expression Language (EL) Implementation
  • Messages in the Default Error View
  • Logging Shutdown Hooks
  • Gradle Default jar and war Tasks
  • Cassandra Throttling Properties
  • Customizing jOOQ’s DefaultConfiguration
  • Groovy 3
  • Minimum Requirements Changes
  • Hibernate Validator 6.2

위에 나온 내용 이외에도 업그레이드 되면서 deprecated 되는 것들에 대한 부분들, 그리고 새로 추가 된 부분들에 대한 설명을 하나하나 읽어보고 현재 내가 담당하는 프로젝트에서 사용되는 것들과 연관된 것들을 모두 읽어보았습니다.

그리고 spring boot 버전을 변경한 뒤 오류가 발생하는 부분은 없는지 배포는 잘 되는지를 확인했습니다.

boot 업그레이드 작업하면서 변경했던 부분은 아래 내용들이었습니다.

  • spring.config.use-legacy-processing = true 설정을 추가
  • fasterxml.jackson.databind.PropertyNamingStrategy -> PropertyNamingStrategies 클래스 변경
  • third-party dependency 들 중에서 업그레이드가 필요한 것들 확인 및 업그레이드
  • gradle 버전 업그레이드 6.7 -> 6.9

작업 내용만보면 진짜 별거 아니었던 작업으로 보이네요. 작업시간보다 문서 읽어보는 시간이 더 오래 걸렸던것 같습니다. 링크를 타고타고 들어가야 확인할 수 있는 것들이 많다보니..

아무튼 로컬환경에서 잘 돌아가는 것까지 확인 하고 개발에 올려 테스트를 해보니 애플리케이션이 정상적으로 실행되지 못하는 현상이 확인되었습니다. 왜 그런가 봤더니 jar 파일명이 이상하게 바뀌어있었습니다. 끝에 -plain postfix가 붙은 파일명이 배포된 것을 확인했고 이게 뭔가 싶어 구글링을 해보니 release note 에서 설명을 찾아볼 수 없었지만(내가 못 본 걸수도?) 2.5버전부터 발생하는 현상이었고 gradle 설정에서 jar task를 비활성화 시키거나 배포파일을 만드는 task 에서 해당 파일을 exclude 처리하면 되는 문제였습니다.

 

매일 반복되는 특별하지 않은 업무들만 하다가 처음으로 해본 프레임워크 업그레이드 작업은 너무 재미있었고 좋은 경험이었습니다.

 

내년에는 java 17 + SpringBoot 3 기반의 신규 프로젝트를 하나 만들어야 하는데 벌써부터 기대되고 현재 사용중인 java 11 에서 17까지 어떤 변화들이 있었는지 확인하는 시간을 가져야 할 것 같습니다.

 

개인프로젝트를 하다보면 한동안 작업진행을 못하다가 다시 재개하는 경우가 많은데

이때 노트북을 새로 바꾸었거나, 프로젝트 디렉토리를 잘못해서 삭제했다가

다시 git clone 할 때 Invalid username or password 를 보게 된다.

github 에서 https 주소로 clone 을 하거나

토근유효기간을 넘겨서 git push를 하게되면

invalid 오류가 발생하게 된다.

1년에도 여러번 이런 일이 발생하는데

어떻게 처리해야하는지 자꾸 까먹어서 기록용으로 남깁니다.

Github 계정의 Settings > Developer Settings 로 가서

Personal Access Token(이하 PAT) 을 재생성(regenerate)합니다.

그리고 git clone 의 경우 아래처럼 clone 명령을 입력합니다.

https://계정명:PAT@github.com/클론할_repo의 주소

git push 의 경우 username과  password 를 입력하는 프롬프트가 뜨게되는데

이때 password 에 github 웹 로그인시 입력하는 password 가 아닌 PAT 를 입력하면됩니다. 

포스팅을 너무 오랜만에 하네요.

요즘은 회사사정도 별로고 회사업무에서 배우는 것도 뭐 없다보니 블로그에 글을 잘 안쓰게 되네요.

하지만!!!! 성장에 대한 욕구는 아직도 초심과 같다는... ㅎㅎ

flutter 에 매료된 올해 초부터 flame 을 이용하여 게임개발을 진행했었습니다.

1일차 이후로 포스팅을 하지 않았지만

flutter와 flame 공식문서 읽어가면서 짬짬이 개발을 진행했고

5월 31일 구글플레이에 출시됐습니다.

대략 주 2회 밤샘 작업으로 진행을 했으니 실제 개발기간은 2개월정도 될 것 같네요

일단 결과물이 어떻게 나왔는지 보고 싶으실 것 같아 구글플레이 링크를 하나 남깁니다

https://play.google.com/store/apps/details?id=com.keichee.exterminate_mosquitoes&hl=ko-KR

 

모기 헌터 - Google Play 앱

인류 최대의 해충! 모기를 박멸하고 지구를 구해주세요

play.google.com

 

모기를 잡으면서 여섯가지 종류의 모기들을 수집하고,

능력치를 향상시키면서 더 높은 stage 로 올라가고,

광고시청으로 레벨업에 필요한 코인(?)을 추가획득 할 수 있습니다.

리더보드도 추가해볼 예정입니다.

💻 Programming/Flutter & Dart & Flame

[Flame] 게임 개발 1일차

요즘 flutter & flame 으로 1인게임 개발을 진행하고 있는데 알아야 할게 너무나도 많아 문서 찾아보고 유툽 영상 찾아보면서 얕은 지식을 조금씩 조금씩 모으다가 지겨워져서 엊그제 하루 날 잡아서 퇴근하고 밤새워 구글링해가면서 만들어봤습니다.

인트로 화면도 로비화면도 없고 그냥 모기 날아다니게 만들고 터치하면 HP 줄어들면서 사라지고 단계별로 정해진 모기들을 모두 잡으면 다음 단계로 넘어가도록 했습니다. 아래는 샘플 영상입니다.

 

원래 단계별로 일정 마리수의 모기가 나오도록 해놓았으나 단계별로 모기마리수를 제외하면 특별할게 없어서 단계당 한마리씩만 출몰하도록 설정을 변경한 뒤 녹화했습니다. 단계별로 모기의 HP도 늘어납니다. ㅎㅎ

아직 해야할게 많이 있지만 중간중간 기록을 위해 포스팅합니다.

앞으로 해야할 것들은... HP바 만들기... 유저 로그인 및 최종게임상태 저장하기, 리더보드, 모기의 유저공격 기능, 유저 및 모기 공격력, 장비&스킬, 보스급모기, 보스출현시 애니메이션 등등 기획하기 및 그림그리기 등등... 너무 많이 있지만 천천히 끝까지 가보려고 합니다 ㅎ

 

flutter 에 입문한지 2주정도 되가는것 같네요

우연히 유툽통해서 접한뒤로 반해가지고 실제 업무에서 쓸일은 없을 것 같지만 모바일앱이든 웹이든 1인개발용으로 너무 좋을 것 같아 입문했습니다.

한 2주동안 책 구입해서 읽고, 공식문서 읽고, 책 예제와 코드랩 예제들 그리고 유툽 예제들 따라해보고나서,

간단한 타자연습 앱을 만들어 봤는데 어떤 위젯을 사용할지부터해서 처음부터 끝까지 오로지 제 생각만으로 하나 만들어보았습니다. (예제 따라하기는 코드랩이 제일 배우기 좋았던 것 같습니다)

타수계산할때 한글은 영어보다 까다로울 것 같아 영문버전으로만 만들었습니다.

이것저것 더 추가하고 싶은 기능(리더보드, 실시간 배틀)들도 있고 flame 을 이용해서 타자를 이용한 여러 게임모드들을 추가하는 등 좀더 게임스럽게 꾸며보고도 싶은데 일단 그냥 기록용도로 남겨봅니다.

매우 간단한 앱이지만 flutter와 더 친숙해질 수 있었던것 같아 매우 유익했던 시간이었네요.

모바일 앱 버전과 웹 버전을 분기태워서 조금 다르게 가져갈 수도 있었는데 아직은 웹보다는 앱개발에 더 최적화된 프레임워크인 것 같습니다.

이제 슬슬 flame 으로 넘어가보려 합니다 :)

자판 연습용 앱

 

아래 영상은 첫 날 설치해서 실행해본 데모앱의 내용을 다 지우고 처음부터 작성하면서 화면 이동, 각종 버튼 추가, 그리고 버튼에 이벤트 핸들링 기능을 넣어보는 기초적인 부분에 대해서 빠르게 가르쳐 주고있습니다. 처음 플러터를 접하는 분들에게 딱 좋은 영상인것 같아서 공유합니다.

 

https://www.youtube.com/watch?v=C-fKAzdTrLU 

 

그리고 플러터 공식문서에서도 Cookbook 에서 기본적으로 필요한 기능들에대해 어떻게 구현해야하는지 예제샘플들을 갖추고 있고, codelab 이라는 단계별 따라해보기와 같은 자료도 제공해주고 있습니다. 코드랩을 따라해보면 앱을 개발할때 어떻게 개발이 진행되는지 그 순서도 배울 수 있습니다.

구글에서 엄청나게 밀고있다는게 느껴질 정도로 기반자료들이 매우 많이 있네요.

플러터를 써보려다가 다트를 공부하기 시작..

Dart 가 어떤 언어인지에대한 간략한 소개내용을 공식문서에서 읽어봤습니다.

얼핏 보니 자바와 매우 유사합니다.

객체지향 언어이고 변수, loop, 메서드, 클래스 등등 매우 많은 부분에서 유사한 점을 보이고 있음.

자바와 다트의 차이점을 나열해보자면..다트는 아래와 같은 특징 또는 기능이 있습니다.

  • primitive(원시) 타입이 없음. 자바의 경우 int, long, double 과 같은 원시타입과 이 원시타입들의 wrapper 클래스인 Integer, Long, Double 등이 존재하지만, 다트는 모든 타입이 Object 임.
  • 변수 사용법 (출력시 문자열을 "이걸 출력할건데 변수명을 붙였어요 $변수명" 이렇게 써주면 $변수명 이 변수가 들고있는 값으로 치환되어 출력됨. 자바의 경우 String.format 을 이용해야 했음), 변수명 자리에 {expression} 을 사용하여 계산식을 사용할 수도 있음
  • null safety (Dart 2.12 버전부터 생김. 자바의 NPE 예방을 개발자가 아닌 컴파일러가 해주도록 한 기능으로 기본적으로 모든 객체는 non-nullable 로 취급함. 다만 ? 기호를 이용해서 nullable 객체라고 명시적으로 선언하면 null 값도 사용할 수 있음, 공식문서 참고)
  • private, protected, public, default 같은 접근제한자(access modifier)가 없음. 다만 이름이 밑줄로 시작하면 해당 라이브러리(클래스?)에 private한 것이 됨.
  • 다트의 int 타입은 64 비트 signed 값이고 플랫폼에 따라 범위가 약간 다름 (공식문서)

뭐 이외에도 lexical scope, lexical closure 등 여러 부분에서 다른 부분들이 보였는데 여기 다 나열할 수는 없고,

전체적인 느낌은 자바와 자바스크립트를 합쳐놓은 언어라는 느낌을 받았습니다. (해본게 Java랑 Javascript 뿐이라.. ㅎ)

 

참고로 다트패드에서 이런저런 다트코드들을 시험해볼 수 있습니다.

우연히 어떤 1인 개발자의 이야기를 유툽에서 접하고 나도 1인 개발이나 해야겠다 생각하던 찰나 또 우연히 플러터 강사의 영상을 본 뒤 목표를 달성하기 위한 매우 매력적인 프레임워크라는 생각이 들어서 플러터에 대해서 알아보려고 합니다. 

 

우선 공식 사이트에서 플러터가 뭔지부터 확인을 좀 해봤는데요

플러터는 구글에서 만든 크로스플랫폼 UI 프레임워크입니다.

모바일(안드 , IOS 둘다), 데스크탑 앱(Windows .exe 파일, MacOS .dmg파일), 웹 까지 모두 하나의 소스코드로 배포가 가능하죠.

이런게 바로 슈퍼앱이 아닌가 싶네요. 여기까지하고 일단 무작정 따라해봅니다.

 

아래 링크의 설명대로 명령어를 실행한다.

https://docs.flutter.dev/get-started/install/macos

 

macOS install

How to install on macOS.

docs.flutter.dev

 

1.  sudo softwareupdate --install-rosetta --agree-to-license

Password:
By using the agreetolicense option, you are agreeing that you have run this tool with the license only option and have read and agreed to the terms.
If you do not agree, press CTRL-C and cancel this process immediately.
2023-01-18 17:11:11.031 softwareupdate[62998:409413] Package Authoring Error: 012-92132: Package reference com.apple.pkg.RosettaUpdateAuto is missing installKBytes attribute
Install of Rosetta 2 finished successfully

뭔가 에러가 났는데 성공적으로 설치했다고 나오네요 !?

 

2. flutter docter 

아래처럼 이쁘게도 분석 결과를 보여주는군요

일단 X표시가 뜬 것들을 설치해야겠어요..

 

  • 안드로이드 스튜디오 설치 및 최초실행하여 sdk 다운로드, 라이센트 동의, cli tool 설치 등 완료
  • Xcode 설치 완료 및 라이센스 관련 오류 해결

 

현재 CocoaPods 이슈와 안드로이드 스튜디오에서 번들자바가 없다는 warning만 남기고 해결.

 

VS Code 를 IDE로 선택해서 테스트앱 생성, 실행 및 수정하여 hot reload 까지 확인완료.

 

다음엔 https://docs.flutter.dev/get-started/codelab 여기부터 진행 예정.

 

이었으나... 버전이 다른건지 신규 프로젝트 생성시 샘플 예제가 달라서 일단 dart 언어에 대해 알아보기로 함...

얼핏 봤을 때는 자바와 매우 비슷함..