티스토리 뷰

 

이번 프로젝트는 핵심기능부터 먼저 만들어 사용하기 위해 TDD를 사용해 진행하기로 했다.

 

지금까지 핵심테이블,인터페이스의 구현이 완료되었으니

식단 생성의 핵심기능중 BMR, 일일소비칼로리의 계산기능을 만들기전 단위테스트 먼저 작성하기로 했다.

 

이전에 생성해온 프로젝트에서는 JUnit4를 사용해 단위테스트를 사용했었는데

이번 프로젝트는 JUnit5를 사용하고 assertj 라이브러리등 테스트코드의 가독성을 높이고

좀 더 사용하기 편한 친구들을 통해 원활한 단위 테스트를 진행하기 위해 별도의 설정을 해주기로 했다.

 

먼저 JUnit4에서 5로 버전 변경을 위해 pom.xml에서 dependency를 수정해주어야 한다.

 

기존의 JUnit4로 되어있는 dependency를 지우고, 다음의 dependency를 추가해준다.

 

		<!-- Test -->
		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter</artifactId>
			<version>${junit-jupiter.version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.junit.platform</groupId>
			<artifactId>junit-platform-runner</artifactId>
			<version>${junit-platform.version}</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.assertj</groupId>
			<artifactId>assertj-core</artifactId>
			<version>3.12.2</version>
			<scope>test</scope>
		</dependency>

 

이때 버전은 다음과 같다.

 

		<junit-jupiter.version>5.5.0</junit-jupiter.version>
		<junit-platform.version>1.2.0</junit-platform.version>

 

 

이제 JUnit5에서 부터 지원되는 @DisplayName등의 어노테이션을 사용한 단위테스트가 가능하겠다.

assertj라이브러리에서 지원되는 테스트 작성시 가독성을 높여주는 isEqualTo등의 메소드의 활용이 가능하다.

 

그리고 이제 핵심기능의 단위테스트를 작성해보려 한다.

지금 구현하려는 기능은 BMR, 칼로리 계산이므로 서비스단에서 처리하는게 맞다고 판단이 들어 서비스 인터페이스와 사용자의 정보를 전달받을 VO 먼저 구현해주도록 했다.

 

키,몸무게,나이,성별을 매핑될수 있도록 해주고,

 

public class UserVO {
	
	private double height;
	private double weight;
	private int age;
	private boolean gender;
   
   
    ...
}

 

 

해당 정보로 BMR을 계산하는 기능과

활동계수와 BMR을 통해 일일사용칼로리를 계산하는 기능을 만들것이다.

(이 인터페이스를 구현받는 클래스는 그냥 생성만 해두도록 한다.)

 

public interface IF_DailyMealService {

	public int calculateBMR(UserVO userVO);
	public int calculateCalories(int BMR, int activity);
	
}

 

 

대강 어떠한 기능을 만들것이다하는 이름짓기 과정이 마무리 되었으니 단위 테스트를 작성해 보도록하겠다.

 

단위테스트를 작성할 클래스의 디렉토리 위치는 src/test/java에서 작성해 테스트임을 구분해 생성한다.

이때 접미사로 Test를 붙여 테스트 클래스임을 명시해준다.

 

 

 

현재 테스트하려는 객체가 Service단이므로 필드로 선언후 객체 주입을 받아 테스트 메소드에서 활용할수 있도록 하고 싶었다.

 

	@Autowired
	private IF_DailyMealService dailymealService;

 

 

그리고 현재 인터페이스에서 정의해둔 두가지 기능에 대한 단위 테스트를 작성해 주었다.

 

	@ParameterizedTest
	@DisplayName("사용자의 정보로 BMR계산후 리턴")
	@CsvSource(value = {"175:75:26:true:1719", "160:48:23:false:1204", "159:43:22:false:1153"}, delimiter = ':')
	void calculateBMRByUserInfo(double height, double weight, int age, boolean gender, int BMR) {
		
		UserVO userVO = new UserVO();
		userVO.setWeight(weight);
		userVO.setHeight(height);
		userVO.setAge(age);
		userVO.setGender(gender);
		
        assertThat(dailymealService.calculateBMR(userVO)).isEqualTo(BMR);
	}
	
	@ParameterizedTest
	@DisplayName("사용자의 BMR정보와 운동계수로 일일 칼로리소모량 계산후 리턴")
	@CsvSource(value = {"1719:2:2664", "1204:0:1445", "1153:1:1585"}, delimiter = ':')
	void calculateCaloriesByUserBMRAndActivity(int BMR, int activity, int calories) {
		 assertThat(dailymealService.calculateCalories(BMR, activity)).isEqualTo(calories);
	}

 

 

그리고 정상적으로 실행되는지 테스트 코드를 실행 시켜본 결과,

 

예?

 

구글링 해본결과, 많은 사람들이 JUnit의 실행 버전을 4로 낮추는 방법을 제시하고 있었다.

그러나 내가 사용하고 싶은건 JUnit5지 4가 아니므로 조금 더 찾아본 결과

 

다음의 결과를 찾을 수 있었다.

 

https://stackoverflow.com/questions/50323335/java-lang-nosuchmethoderror-org-junit-platform-launcher-launcher-execute

 

java.lang.NoSuchMethodError: org.junit.platform.launcher.Launcher.execute

I'm trying to run the following example unit test case class ExampleUnitTest { @Test fun addition_is_Correct() { assertEquals(4, (2 + 2).toLong()) } } but I get the following

stackoverflow.com

 

 

junit-platform-launcher의 버전이 1.4 이상일때만 JUnit5의 사용이 가능하다

 

그래서 버전변경을 1.4.2로 해주었다.

 

<junit-platform.version>1.4.2</junit-platform.version>

 

 

이제 다시 실행을 시켜보니...

 

예?

 

객체 주입을 받아 사용하려는 필드를 root-context.xml에서 빈등록을 해주었고,

@Autowired 어노테이션을 붙였음에도 주입을 받지 못하고

null인상태로 계속 있게 되어 에러가 발생하는 상황이 되었다.

 

역시 구글링을 해본결과,

 

스프링4.x.x 는 JUnit4와 호환이 좋고 JUnit5는 5버전 이상을 사용하는게 좋다란 의견이 있어

스프링 버전부터 5버전 이상으로 올려주었다.

 

<org.springframework-version>5.0.7.RELEASE</org.springframework-version>

 

 

그럼에도 계속 에러가 발생해서 좀 더 찾아본결과 테스트 클래스 상단에 

@ContextConfiguration등의 어노테이션을 사용해 빈등록한 applicationContext 경로를 명시해주는 방법등을

찾게 되었다.

 

그래서 해당 어노테이션의 사용을 위해 추가로 Spring-test dependency 설정을 해주었다.

 

		<!-- 스프링 테스트 라이브러리 추가 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${org.springframework-version}</version>
			<scope>test</scope>
		</dependency>

 

 

그리고 현재 빈등록을 해둔 설정파일인 root-context.xml로 경로 설정을 해주고 실행시켜보았다.

 

@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:root-context.xml")
public class DailyMealServiceTest {

...

}

 

 

그러나 문제는 해결되지 않았다.

대신 새로운 에러문구를 발견할수 있었다.

 

java.io.FileNotFoundException: class path resource [root-context.xml] cannot be opened because it does not exist


분명 root-context.xml이란 파일이 존재함에도 파일을 찾지 못한다는 메세지이다.

늘 그렇듯 컴퓨터는 거짓말을 하지않고 문제는 나에게 있으므로 학습이 필요한 시간이다.

 

 

학습의 결과 스프링 maven 프로젝트는 

src/main/java 디렉토리일 경우는 src/main/resources 에서 설정한 설정 파일로 적용되어 등록된 빈등을

가져와 객체 주입이 진행된다.

그러나 현재 우리의 단위테스트의 디렉토리는 src/test/java에 존재하고

src/test/resources 역시 별도로 존재함을 확인 할수 있다.

 

 

 

그리고 설정을 해주었다 생각한 root-context.xml의 위치를 확인 해보도록 하겠다.

 

cmd에서 프로젝트의 src 디렉토리 트리를 조회하면 다음과 같다.

 

C:.
├─main
│  ├─java
│  │  └─com
│  │      └─human
│  │          ├─dailymeal
│  │          │      HomeController.java
│  │          │
│  │          ├─dao
│  │          │      FoodDetailImpl.java
│  │          │      FoodImpl.java
│  │          │      IF_FoodDAO.java
│  │          │      IF_FoodDetailDAO.java
│  │          │      IF_MenuDAO.java
│  │          │      IF_MenuDetailDAO.java
│  │          │      MenuDetailImpl.java
│  │          │      MenuImpl.java
│  │          │
│  │          ├─service
│  │          │      DailyMealServiceImpl.java
│  │          │      IF_DailyMealService.java
│  │          │
│  │          └─VO
│  │                  FoodDetailVO.java
│  │                  FoodVO.java
│  │                  MenuDetailVO.java
│  │                  MenuVO.java
│  │                  UserVO.java
│  │
│  ├─resources
│  │  │  log4j.xml
│  │  │
│  │  ├─mapper
│  │  │      FoodDetailMapper.xml
│  │  │      FoodMapper.xml
│  │  │      MenuDetailMapper.xml
│  │  │      MenuMapperxml.xml
│  │  │
│  │  └─META-INF
│  └─webapp
│      ├─resources
│      └─WEB-INF
│          │  web.xml
│          │
│          ├─classes
│          ├─spring
│          │  │  root-context.xml
│          │  │
│          │  └─appServlet
│          │          servlet-context.xml
│          │
│          └─views
│                  home.jsp
│
└─test
    ├─java
    │  └─com
    │      └─human
    │          ├─dailymeal
    │          └─service
    │                  DailyMealServiceTest.java
    │
    └─resources
            log4j.xml

 

 

이제 root-context의 위치를 보면 src/main/resources 하위에 존재함을 알 수 있고

우리의 테스트코드 클래스는 src/test/java에 존재함을 알 수 있게 된다.

 

즉 경로롤 못찾겠다란 컴퓨터의 말이 다시 한번 옳은걸 알게되었다.

 

그럼 해결방법은 이제 다 나왔다.

 

src/test/resources 하위에 별도의 context 파일을 생성해 거기서 별도로 빈등록을 해주어

테스트용 객체주입을 시켜주면 된다.

 

파일이름은 test-context로 하도록 하겠다.

 

그리고 파일 생성후 빈등록을 해준다면...

 

<?xml version="1.0" encoding="UTF-8"?>
<!-- test-context.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 테스트용 패키지 스캔 설정 -->
    <context:component-scan base-package="com.human.service"/>
</beans>

 

 

콘솔에서도 정상적으로 객체주입이 일어난것을 확인할수 있는 메세지가 나오고

 

INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@15761df8, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@6ab7a896, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@327b636c, org.springframework.test.context.support.DirtiesContextTestExecutionListener@45dd4eda, org.springframework.test.context.transaction.TransactionalTestExecutionListener@60611244, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@3745e5c6]
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [test-context.xml]
INFO : org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@3d74bf60: startup date [Sat Dec 09 14:10:24 KST 2023]; root of context hierarchy
INFO : org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
INFO : org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@3d74bf60: startup date [Sat Dec 09 14:10:24 KST 2023]; root of context hierarchy

 

 

단위테스트 창에서도 원하는 결과인 단위테스트 실패 메세지를 확인 할수 있게 된다.

 

아직 메소드를 작성하지 않았으니 실패하는것이 맞다.

 

 

 

'웹 개발 > 식단 생성기 프로젝트' 카테고리의 다른 글

DAO interface 설계  (2) 2023.12.06
프로젝트 초기 설계  (1) 2023.12.03
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함