TDD(Test-driven Development) ํ ์คํธ ์ฃผ๋ ๊ฐ๋ฐ๋ฐฉ๋ฒ๋ก
๊ฐ์ข Community์์ ๊ฐ๋ฐ ํ๋ก์ธ์ค๊ฐ TDD๊ฐ ์ธ๊ธ์ด ๋์๊ณ ์์ ์ ์ํํธ์จ์ด ๊ฐ๋ฐ ํ๋ก์ธ์ค ์ค์ ๋ฐฐ์ ๋ TDD์ ๋ํด ๊น์ด ์๊ฒ ๋ชฐ๋๊ธฐ ๋๋ฌธ์ ๋ช ํํ๊ฒ ์ ์๋ฅผ ํ๊ณ ์์ผ๋ก ๊ฐ๋ฐ ๋ฐฉ๋ฒ์ TDD๋ก ๋ฐ๊พธ๋ ค๊ณ ๋ ธ๋ ฅํ๊ธฐ ์ํด Posting์ ํด๋ณด๋ ค๊ณ ํ๋ค.
1. TDD(Test-driven Development)์ด๋?
-
์ผ๋ฐ์ ์ธ ๊ฐ๋ฐ ํ๋ก์ธ์ค
- ์ผ๋ฐ์ ์ผ๋ก ๊ฐ๋ฐ ์ ์ฐจ๋ ๋จผ์ ์ด๋ป๊ฒ ๊ฐ๋ฐํ ์ง ๋์์ธํ๊ณ ๋์์ธ์ ๋ฐํ์ผ๋ก ์ค์ ์ฝ๋๋ฅผ ์์ฑํ๊ณ ์ต์ข ์ ์ผ๋ก ํ ์คํธ๋ฅผ ์๋์์ผ๋ณด๋ฉด์ ํด๋ณด๋ ๊ณผ์ ์ด์๋ค.
-
TDD(Test-driven Development)
- ์ ํํ ํ๋ก๊ทธ๋๋ฐ ๋ชฉ์ ์ ๋์์ธ ๋จ๊ณ์์ ๋ฐ๋์ ๋ฏธ๋ฆฌ ์ ์ํด์ผ๋ง ํ๊ณ ๋ ๋ฌด์์ ๋ฏธ๋ฆฌ ์ ์ํด์ผํ๋ค.
- RED : ์คํจํ๋ ํ ์คํธ๋ฅผ ๋ง๋ค๊ธฐ.
- GREEN : ํ ์คํธ์ ํต๊ณผํ ๋งํ ์์ ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ.
- REFACTOR : ๋ฐ๋ณต๋๋ ์ฝ๋, ๊ธด ๋ฉ์๋, ํฐ ํด๋์ค, ๊ธด ๋งค๊ฐ๋ณ์ ๋ชฉ๋ก ๋ฑ๋ฑ ์ฝ๋๋ฅผ ์ข ๋ ํจ์จ์ ์ผ๋ก ๋ฐ๊พธ๊ธฐ.
- ๊ฐ๋ฐํ๋ ๊ณผ์ ์์ Test Script๋ฅผ ์์ฑํ๊ณ ์ฝ๋๋ฅผ Refactoring ํ๋ค๋ ์ ์ด ์ค์ํ๋ค.
2. TDD ๋ฐ๋ผํ๊ธฐ (JUnit)
๋ชฉํ : Movie๋ผ๋ ํด๋์ค์ ๋ฑ๊ธ์ ๋ถ์ฌํ๊ณ Averaging Rate๊ตฌํ๊ธฐ
1) JUnit์ด๋?
- ๋ฒ์ฉ์ ์ผ๋ก ์ฌ์ฉ๋๋ ๋จ์ ํ ์คํธ Framework
- Java ์ธ์ด์ ๋จ์ ํ ์คํธ๋ฅผ ์ํด ์ฌ์ฉ๋๋ค.
- ๋ ์์ธํ ๋ด์ฉ์ JUnit Post https://nesoy.github.io/articles/2017-02/JUnit๋ฅผ ์ฐธ๊ณ ํ๋ฉด ๋๋ค.
2) pom.xml JUnit & Hamcrest ์ถ๊ฐ ์ฝ๋
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
</dependencies>
3) JUnit ์คํ
package movie;
import org.junit.Test;
/**
* Created by NESOY on 2017-01-31.
*/
public class MovieTest {
@Test
public void foo(){
}
}
Test ๊ฒฐ๊ณผํ๋ฉด
4) Failing Test ์ฝ๋ ์์ฑ
/**
* Created by NESOY on 2017-01-31.
*/
public class MovieTest {
@Test
public void canCreateMovie(){
Movie movie = new Movie();
}
}
5) Test๋ฅผ ํต๊ณผํ๊ธฐ ์ํ ์๋์ ์ฝ๋ ์ถ๊ฐ
package movie;
/**
* Created by NESOY on 2017-01-31.
*/
public class Movie {
}
Test ๊ฒฐ๊ณผํ๋ฉด
6) Averaging Rating Test Case๋ง๋ค๊ธฐ - ๊ฐ์ฅ ์ด๊ธฐ ๋ชจ๋ธ์ด๋ฏ๋ก Rate์ ์๊ฐ ์๋ค. โ 0์ .
package movie;
import org.junit.Test;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
/**
* Created by NESOY on 2017-01-31.
*/
public class MovieTest {
@Test
public void canCreateMovie(){
Movie movie = new Movie();
assertThat(movie.averageRationg(),is(0));
}
}
7) Test๋ฅผ ํต๊ณผํ๊ธฐ ์ํ ์๋์ ์ฝ๋ ์ถ๊ฐ
package movie;
/**
* Created by NESOY on 2017-01-31.
*/
public class Movie {
public Integer averageRationg() {
return 0;
}
}
Test ๊ฒฐ๊ณผํ๋ฉด
8) Refactoringํ๊ธฐ - Method ์ด๋ฆ ๋ฐ๊พธ๊ธฐ
package movie;
import org.junit.Test;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
/**
* Created by NESOY on 2017-01-31.
*/
public class MovieTest {
@Test
public void should_return_0_when_just_created(){
Movie movie = new Movie();
assertThat(movie.averageRationg(),is(0));
}
}
9) Averaging Rating Test Case๋ง๋ค๊ธฐ โ 1์ ์ฃผ์์๋ Average Rate๊ฐ 1์ด ๋์์ผํ๋ค.
package movie;
import org.junit.Test;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
/**
* Created by NESOY on 2017-01-31.
*/
public class MovieTest {
@Test
public void should_return_0_when_just_created(){
Movie movie = new Movie();
assertThat(movie.averageRationg(),is(0));
}
@Test
public void should_return_1_when_was_rated(){
Movie movie = new Movie();
movie.rate(1);
assertThat(movie.averageRationg(),is(1));
}
}
10) Compile ํต๊ณผํ๊ธฐ ์ํ ์๋์ ์ฝ๋ ์ถ๊ฐ
package movie;
/**
* Created by NESOY on 2017-01-31.
*/
public class Movie {
public Integer averageRationg() {
return 0;
}
public void rate(int rate) {
}
}
Test ๊ฒฐ๊ณผํ๋ฉด
averageRationg Return ๊ฐ์ด ์ด๋ ํ ์ํฉ์์๋ 0์ด๋ค. ๊ณ ์ณ์ Test๋ฅผ ํต๊ณผ์ํค์.
package movie;
/**
* Created by NESOY on 2017-01-31.
*/
public class Movie {
private int sumOfRate = 0;
private int countOfRate = 0;
public Integer averageRationg() {
return sumOfRate/ countOfRate;
}
public void rate(int rate) {
this.sumOfRate += rate;
this.countOfRate++;
}
}
Test ๊ฒฐ๊ณผํ๋ฉด
countOfRate๊ฐ 0์ผ ๊ฒฝ์ฐ์ 0์ผ๋ก ๋๋์์ ๊ฒฝ์ฐ Exception ๋ฐ์ โ 0์ผ๋ ์์ธ์ฒ๋ฆฌ
package movie;
/**
* Created by NESOY on 2017-01-31.
*/
public class Movie {
private int sumOfRate = 0;
private int countOfRate = 0;
public Integer averageRationg() {
return countOfRate == 0 ? 0 : sumOfRate/ countOfRate;
}
public void rate(int rate) {
this.sumOfRate += rate;
this.countOfRate++;
}
}
Test ๊ฒฐ๊ณผํ๋ฉด
11) Refactoring - TestCase์ ์ค๋ณต๋๋ ๋ถ๋ถ ์ ๊ฑฐํ๊ธฐ
package movie;
import org.junit.Test;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
/**
* Created by NESOY on 2017-01-31.
*/
public class MovieTest {
@Test
public void should_return_0_when_just_created(){
Movie movie = new Movie(); // ์ค๋ณต
assertThat(movie.averageRationg(),is(0));
}
@Test
public void should_return_1_when_was_rated(){
Movie movie = new Movie(); // ์ค๋ณต
movie.rate(1);
assertThat(movie.averageRationg(),is(1));
}
}
Tips : Intellj Refactor - Field - Setup Method ์๋์ผ๋ก ํด์ค๋ค.
package movie;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
/**
* Created by NESOY on 2017-01-31.
*/
public class MovieTest {
private Movie movie;
@Before
public void setUp() throws Exception {
movie = new Movie();
}
@Test
public void should_return_0_when_just_created(){
Movie movie = this.movie; // ๋ถํ์ํ๋ฏ๋ก ์ ๊ฑฐํ๋ค.
assertThat(movie.averageRationg(),is(0));
}
@Test
public void should_return_1_when_was_rated(){
Movie movie = this.movie; // ๋ถํ์ํ๋ฏ๋ก ์ ๊ฑฐํ๋ค.
movie.rate(1);
assertThat(movie.averageRationg(),is(1));
}
}
12) Averaging Rating Test Case๋ง๋ค๊ธฐ โ 3,5์ ์ฃผ์์๋ Average Rate๊ฐ 4์ด ๋์์ผํ๋ค.
@Test
public void should_return_4_when_3_and_5_were_rated(){
movie.rate(3);
movie.rate(5);
assertThat(movie.averageRationg(),is(4));
}
Test ๊ฒฐ๊ณผํ๋ฉด
3. ์ค์ ๋ก ํด๋ณธ TDD ์ฅ์
- ๋๋ฒ๊น ์๊ฐ์ ๋จ์ถ์ด ๋งค์ฐ ๋จ์ถ๋๋ ๊ฑธ ๋๋ ์ ์๋ค.
- ์ถ๊ฐ ๊ตฌํ์ด ๋งค์ฐ ์ฝ๊ณ ๊ฐ๋จํ๋ค.
- ๋ฆฌํฉํ ๋ง ๊ณผ์ ์์ ์ง์์ ์ผ๋ก ์ฝ๋๋ฅผ ๊ฐ์ ํ๊ธฐ ๋๋ฌธ์ ์ฌ์ค๊ณ ์๊ฐ์ ๋จ์ถ๋๋ค.
๊ฒฐ๋ก : ๋งค์ฐ ์ข๋ค. ์์ผ๋ก ์ต๊ด๋ค์ฌ์ผ๊ฒ ๋ค.
Intellj ๋จ์ถํค
- ํ๋ฉด ๋๋๊ธฐ : Ctrl + Shift + A + Split Vertical
- Refactoring Field : Ctrl + Shift + A + Field ( Ctrl + Alt + F)
Books
- ํ ์คํธ ์ฃผ๋ ๊ฐ๋ฐ - ์ผํธ ๋ฒก