본문 바로가기
  • think normal
새로워지기/서른의 생활코딩

스프링 부트에서 테스트 주도 개발 실습 - 5장. 솔직히 말하자면

by 청춘만화 2019. 2. 27.

STS 4.0.1(스프링 부트)에서 

TDD(테스트 주도 개발 Test Driven Development) 실습하기

 

들어가는 글대다수의 사람들은 다음 두 가지 단순한 법칙을 따름으로써 잠재력을 한껏 발휘할 수 있다.

1. 어떤 코드건 작성하기 전에 실패하는 자동화된 테스트를 작성하라.

2. 중복을 제거하라.


  요구사항 및 개선사항 목록

       - $5 + 10CHF = $10 (환율이 2:1일 경우)

       - $5 x 2 = $10 

- amount를 private로 만들기           

- Dollar 부작용(side effect)?  

- Money 반올림? 

-  equals( )    동질성 기능을 구현  

- hashCode( ) 

- Equal null

- Equal object

       - 신규 : 5CHF X 2 = 10CHF         <- 이번 예제의 목표 

  목적. 테스트 주도 개발의 리듬 이해

1. 재빨리 테스트를 하나 추가한다.

2. 모든 체스트를 실행하고 새로 추가한 것이 실패하는 지 확인한다

3. 코드를 조금 바꾼다.

4. 모든 테스트를 실행하고 전부 성공하는지 확인한다.

5. 리팩토링을 통해 중복을 제거한다.



5장. 솔직히 말하자면 

아, 원제는 Franc-ly Speaking 이다. 이번 장의 예제는 프랑(CHF)으로 환전하는 예제가 진행될 예정이다.


5-0. PREVIOUS 프리비어스 

최근 두 예제(3장, 4장)는 결국 싱글톤 디자인 패턴을 구현한 느낌이다. 

참고로 그리고 4장에서 private(인스턴스 변수)으로 만든 것은 SPRING에서는 지양하기 때문에 싱글톤을 디자인 패턴이 아닌 싱글톤 레지스트리로 사용한다. 관련 내용은 스프링 부트에서 토비 3.1 따라하기 : 1장 - 1.6 싱글톤 레지스트리와 오브젝트 스코프 에서 참고할 수 있다. 


5-1. 첫 요구사항($5 + 10CHF = $10)을 해결하기 위한 교두보 마련 

먼저 Dollar와 같이 프랑스의 화폐 단위를 표현하는 객체가 필요할 것 같다. 객체와 메소드를 각각 복붙하고 필요한 부분만 수정해보았다. 저자는 복붙이 가능한 이유는 테스트를 단순화한(리팩토링) 덕 이라고 했다. 



package com.noramlstory;

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

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestTdd201902 {

	// 5장. 솔직하게 말하면  + Dollar 구문을 복붙했다. 앞서 수행한 리팩토링 덕이다.
	@Test
	public void testFranceMultiplication() {
		Franc five = new Franc(5);
		
		assertEquals(new Franc(10), five.times(2));  
		assertEquals(new Franc(15), five.times(3)); 
	}
	
	// 4장. 프라이버시  
	@Test
	public void testMultiplication() {
		Dollar five = new Dollar(5);

		assertEquals(new Dollar(10), five.times(2));
		assertEquals(new Dollar(15), five.times(3));  
	}
	
	// 3장. 모두를 위한 평등 
	@Test	
	public void testEquality() {
		assertTrue(new Dollar(5).equals(new Dollar(5)));  
		assertFalse(new Dollar(5).equals(new Dollar(6)));
	}
	
}


class Franc{
	private int amount;
	
	Franc(int amount){
		this.amount = amount;
	}
	
	Franc times(int multiplier) {
		return new Franc(amount * multiplier);
	}

	public boolean equals(Object object) {
		Franc franc = (Franc) object;
		return amount == franc.amount;
	}
}

class Dollar{
	private int amount;
	
	Dollar(int amount){
		this.amount = amount;
	}
	
	Dollar times(int multiplier) {
		return new Dollar(amount * multiplier);
	}

	public boolean equals(Object object) {
		Dollar dollar = (Dollar) object;
		return amount == dollar.amount;
	}
}

결과이다. 물론~ 그린라이트. ;D

하지만 코드를 보면 직감적으로? 이번 예제 덕분에 요구사항이 추가될 것임을 알 수 있다.

단순화 해둔 코드 덕에 빨리 컴파일해서 빨리 테스트를 성공할 수 있었지만. 새로운 중복 들이 발생하였다. 

그럼 다시, 

'첫 요구사항($5 + 10CHF = $10)을 해결' 하기 전에 중복을 제거하는 일부터 진행하자고 저자는 말하고 있다. 


5-3. 정리 

1) 큰 테스트('첫 요구사항($5 + 10CHF = $10)을 해결' )를 공략하기 전에 작은 테스트를 만들었다.

2) 뻔뻔스럽게 복붙을 이용하여 빠른 테스트를 성공했지만 중복이 발생했다. 

(1) 저자는 testFranceMultiplication(){...} 메소드를 만드는 과정과

(2) 메소드에 해당하는 class Franc{...} 모델 클래스를 만드는 절차를 나눴다. 나는 너무 순식간에 일어나는 일이라 그냥 한번에 섰다. 

3) 중복이 사라지기 전까지 집에 가지 않겠다고 선언했다. 난 해당사항 없음 ;> 

댓글