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

스프링 부트에서 테스트 주도 개발 실습 - 4장. 프라이버시

by 청춘만화 2019. 2. 23.

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

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

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

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

3. 코드를 조금 바꾼다.

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

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



4장. 프라이버시  


4-1.  PREVIOUS 프리비어스 

다음은 그동안 작성해온 Dollar.class이다. 

class Dollar{
	int amount;
	
	Dollar(int amount){
		this.amount = amount;
	}
	
	Dollar times(int multiplier) {
		return new Dollar(amount * multiplier);
	}
	
	// 3-4 동치성을 일반화 한다 
	public boolean equals(Object object) {
		Dollar dollar = (Dollar) object;
		return amount == dollar.amount;
	}
}

이 클래스는 amount라고 하는 변수를 담아 자신을 그 값을 반환하는 생성자, times(), equals()라는 메소드 들을 가지고 있다. 


3장에서는 equals() 메소드를 통해 동치성을 해결했고 이번 장에서는 times()를 통해 호출받은 객체의 값에 인자로 수만큼 곱한 값을 갖는 Dollar를 반환하도록 할 예정이다. 현재까지는 테스트 코드가 정확히 그것을 말하지는 못하고 있다. 라고 저자는 말한다.

무슨 소리인가 했다. 다 읽어보니 결과는 다르지 않지만 엄밀히 말하면 다르다.  그리고 그 안에 이번 장에서 이루고자 하는 결과가 담겨 있다. 

이전 테스트코드를 보면 "times()를 통해 호출받은 객체의 값에 인자로 받은 수 만큼 곱한 값을 갖는 Dollar를 반환하도록 할 예정이다." 의 과정 중에 product라는 Dollar 오브젝트를 거쳐서 코드가 진행되고 있음을 알 수 있다. 다시말해 위 과정을 수행하는데 위에 밑줄을 두개의 Dollar 오브젝트가 사용되고 있는 것이다. 

이것을 하나로 줄여보자. 


그러면 Dollar 클래스의 인스턴스 변수 amount 를 사용하는 코드는 Dollar 자신밖에 없게 된다. 

여기서 한번 더 궁금증을 갖을 수 있는 부분..  five 도 있고 product 도 있는데 왜 자기 자신이라고 하지? 제 소견으로는 five는 new연산자를 통해 자기 자신을 반환하고 있는 오브젝트이고. product는 그저 Dollar 타입의 변수 에 불과하기 때문이다.


여하튼, 인스턴스 변수 amount 를 사용하는 코드는 Dollar 자신밖에 없기 때문에 amount를 private로 조정할 수 있다. 

자기 자신만 쓸 수 있는 값으로.



4-2.  코드에 반영  

1) assertion 단을 동치성을 반영한 코드로 작성 

2) Dollar products; 및 관련 코드를 소거하고 동치성 코드에 인라인 형태로 병합 


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 TestTdd2019 {
	
        // 4장. 프라이버시 
	@Test
	public void testMultiplication() {
		Dollar five = new Dollar(5);
		
		//assertEquals(10, product.amount);

		assertEquals(new Dollar(10), five.times(2));  // assertion 수정 : 동치성을 반영, product 변수 제거 
		
		assertEquals(new Dollar(15), five.times(3));  // assertion 수정 : 동치성을 반영, product 변수 제거 
	}
	
	// 3장. 모두를 위한 평등 
	@Test	
	public void testEquality() {
		// 3-1. 일단 테스트를 진행한다.  $5 == $5    ( $5 같다 $5 )
		assertTrue(new Dollar(5).equals(new Dollar(5)));  
		
		// 3-3. 삼각 측량을 위해 거짓 비교?를 하나 추가 해본다.    $5 != $6	( $5 같지않다 $6 )
		assertFalse(new Dollar(5).equals(new Dollar(6)));
	}
	
}

class Dollar{
	private int amount;
	
	Dollar(int amount){
		this.amount = amount;
	}
	
	Dollar times(int multiplier) {
		return new Dollar(amount * multiplier);
	}
	
	// 3-4 동치성을 일반화 한다 
	public boolean equals(Object object) {
		Dollar dollar = (Dollar) object;
		return amount == dollar.amount;
	}
}


4-3.  결과


4-4.  지금까지의 실습 내용 검토 

1) 오직 테스트를 향상시키기 위해서만 개발된 기능을 사용

2) 두 테스트가 동시에 실패하면 망한다

만약 동치성 테스트가 동치성에 대한 코드가 정확히 작동한다는 것을 검증하는데 실패한다면, 곱하기 테스트 역시 곱하기에 대한 코드가 정확하게 작동한다는 것을 검증하는데 실패하게 된다 고 쓰여있다. 한번 더 번역하면 

이전에 작성한 곱하기 테스트 코드를 동치성 코드 방식으로 수정했으니 동치성 코드가 틀리면 이전에 했던 곱하기 코드도 맞는지 안맞는지 알 길이 없어지지 않겠느냐 는 말로 들린다.

3) 위험 요소가 있음에도 계속 진행

4) 테스트와 코드 사이의 결합도를 낮추기 위해, 테스트하는 객체의 새기능을 사용 

댓글