
์ด๋ฒ ์ฅ์์๋ Test์ ๊ธฐ๋ณธ ๋จ์๊ฐ ๋๋ Unit Test์ ๋ํด์ ์ดํด๋ณผ ๊ฒ์ด๋ค.
๊ฐ๋จํ ์์ ์ ํจ๊ป ์ดํด๋ณด์
์๋์ ๊ฐ์ ์ฝ๋๊ฐ ์๋ค๊ณ ํด๋ณด์
public class Calc {
public int add(int a, int b) {
return a + b;
} //Unit
public int subtract(int a, int b){
return a - b;
} //U kt
}
Unit Test์์๋ add(), subtract()๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ํ ์คํธ๋ฅผ ํด์ ์ ์๋์ ํ๋์ง ํ์ธํด์ผ ํ๋ค
์ด์ ๋ฐ๋ผ ์ ๋ ํ ์คํธ๋ ์๋์ ๊ฐ์ด ์์ฑํ ์ ์๋ค
public class TestCalc {
public void testAdd() {
Calc calc = new Calc();
if (calc.add(1, 2) == 3)
System.out.println("Success");
else
System.out.println("Failure");
}
public void testSubtract() {
Calc calc = new Calc();
if (calc.subtract(2,3) == -1)
System.out.println("Success");
else
System.out.println("Failure");
}
}
์ฌ๊ธฐ์ Test case์ 3๊ฐ์ง ํ์ ์์๋ฅผ ํ์ธํ ์ ์๋ค
์์๋ฅผ ์ดํด๋ณด์
//static์ ์์ฑํ์ง ์์ผ๋ฉด ์ธ๋๋ง๋ค org.junit.~์ ์์ฑํด์ค์ผ ํ๋ค
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.*;
class MyTest {
@BeforeAll
static void initAll() { //๋ชจ๋ ํ
์คํธ ๋ฉ์๋๊ฐ ์คํ๋๊ธฐ ์ ์ ์คํ
}
@BeforeEach
void init() { //๊ฐ ํ
์คํธ ๋ฉ์๋๊ฐ ์คํ๋๊ธฐ ์ ์คํ
}
@Test
void test() { //ํ
์คํธ ๋ฉ์๋ ์ฝ๋
}
@Test
@Disabled("for demonstration purposes")
void skippedTest() { //์คํ x
}
@AfterEach
void tearDown() { //๊ฐ ํ
์คํธ ๋ฉ์๋ ์คํ ํ ์คํ
}
@AfterAll
static void tearDownAll() { // ๋ชจ๋ ํ
์คํธ๊ฐ ๋๋ ํ ํ ๋ฒ ์ํ
}
org.junit.jupiter.api.*๋ฅผ importํด์ผ๋ง ์๋ annotation์ ์ฌ์ฉํ ์ ์๋ค
๋งจ ์ฒ์์ ์ดํด๋ดค๋ add, subtract ๋ฉ์๋์ ์ ๋ ํ ์คํธ๋ฅผ JUnit์ ํ์ฉํ๋ค๋ฉด ์ด๋ป๊ฒ ์์ฑํ ์ ์์๊น?
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.*;
class CalcTest { // test class ์ ์ธ
@Test //์ด๋ ๊ฒ annotation์ ์์ฑํด์ค์ผ ํจ
void testAdd() {
Calc calc = new Calc();
assertEquals(3, calc.add(1,2));
}
@Test
void testSubtract() {
Calc calc = new Calc();
assertEquals(2, calc.subtract(5,3));
}
}
Assertion methods
c:\javac Calc.java C:>javac CalcTest.java C:>java -jar .\junit-platform-console-standalone-1.11.3jar -cp. -c CalcTest

์ด๋ฌํ ์ ๋ ํ
์คํธ๋ฅผ ๋ชจ๋ ์๊ธฐ๋ก ์์ฑํด์ผ ํ ๊น?
์๋์ผ๋ก ์์ฑํด์ฃผ๋ ํ๋ซํผ์ด ์กด์ฌํ๋ค
์์๋ก Agile methods, XP, test-driven development(TDD) ๋ฑ์ด ์๋ค
TDD์ ๋ ์ดํด๋ณด์
์ด ๋ฐฉ๋ฒ์ ๋ฐ๋ณตํ๋ค
๊ธฐ์กด์ ์ฝ๋๋ฅผ ๋ง์น ์ ์๊ธฐ ๋๋ฌธ์ ๊ณ ์ณ์ง ๊ฒ์ด ์์ผ๋ฉด ๊ธฐ์กด์ ๊ฒ๋ค์ด ๋ค ํ
์คํธ๋ฅผ ํต๊ณผํ๋์ง ๋ด์ผํ๋ค
๊ทธ๋ฅ ๋ณด์ฌ์ฃผ๊ธฐ์์ ํ ์คํธ๊ฐ ์๋๋ผ, ์ข์ ํ ์คํธ๋ฅผ ์์ฑํ ์ค ์์์ผ ํ๋ค
ํ ์คํธ๊ฐ ์๋ ๊ฒ๋ณด๋ค ๋๋ฌ์ด ํ ์คํธ๋ผ๋ ์๋๊ฒ ๋ ๋ซ๋ค๊ณ ์๊ฐํ ์ ์๋ค. ์ด๊ฒ์ ํ๋ฆฐ ์๊ฐ์ด๋ค
why?
Test Suite์ ๊ตฌ์ฑ
1. ํ
์คํธ ์ผ์ด์ค
2. ํ
์คํธ ์๋๋ฆฌ์ค
3. ํ
์คํธ ๋ฐ์ดํฐ
4. ํ
์คํธ ํ๊ฒฝ
์ด๋ฌํ test suite์ ์ค์์ฑ
๊ฒฐ๋ก : ํ ์คํธ ์ฝ๋๋ ํ๋ก๋์ ์ฝ๋๋งํผ ์ค์ํ๋ค. ๊นจ๋ํ ํ ์คํธ ์ฝ๋๋ ์ ์ง๋ณด์์ฑ๊ณผ ์ ๋ขฐ์ฑ์ ๋์ฌ์ค๋ค
READABILITY ๊ฐ๋ ์ฑ์ด๋ค!
what makes tests readable?
ํ ์คํธ๋ ์ฝ๋์ ์์ ๊ฐ์ ์ ๊ณตํ๋ค



๋ฌธ์


UnitTest๋ฅผ ์งค ๋๋ 3๋จ๊ณ๋ก ๋๋์ด์ ์์ฑํ๋ ๊ฒ์ด ์ข๋ค
๊ฐ์ ๋ ์ฝ๋์๋ ๋ํ ์ผ๋ ์ฌ๋ผ์ง๊ณ , ์ค๋ณต๋ ์ ๊ฑฐ๊ฐ ๋์๋ค
ํ ์คํธ๋ฅผ ํ๋ค๋ณด๋ฉด ๋์ผํ ๊ณผ์ ์ ํ์ธํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์๋ค
๋ค์ ์์๋ฅผ ์ดํด๋ณด์
@Test
public void turnOnLoTempAlarmAtThreashold() throws Exception {
hw.setTemp(WAY_TOO_COLD);
controller.tic();
assertTrue(hw.heaterState());
assertTrue(hw.blowerState());
assertFalse(hw.coolerState());
assertFalse(hw.hiTempAlarm());
assertTrue(hw.loTempAlarm());
}
์ด ์ฅ๋น๊ฐ ์ ์๋ํ๋์ง ๋ณด๊ณ ์ถ์ ๊ฒ์ด๊ณ , ์ด๋ฅผ ์ํด์๋ 5๊ฐ์ ์์ ์ ์ํํด์ผ ํ๋ ๊ฒฝ์ฐ๋ค
hardware=hw๋ฅผ ์๋ฏธํ๋ฉฐ, ์๋๋ mental mapping์ ํผํ๋ผ๊ณ ํ์๋๋ฐ ํ ์คํธํ ๋๋ ๋ฐ๋ณต์ด ์๋ ๋ง์ด ๋๊ธฐ ๋๋ฌธ์ ํ์ฉํ๋ค
์ ์ฝ๋๋ฅผ ๋ณด๋ฉด ์ด๋ ํ๊ฐ?
true, false๋ง ๊ณ์ ๋ฐ๋๊ณ ๊ฐ์๊ฐ ๋ง์์ ธ ๋์ ์ ๋ค์ด์ค์ง ์๋๋ค
๋์ ์ ๋ค์ด์ค๊ฒ ๊ฐ์ ํด๋ณด์
@Test
public void turnOnLoTempAlarmAtThreashold() throws Exception {
wayTooCold();
assertEquals("HBchL", hw.getState());
}
๋ก ์ฝ์ด๋ฅผ ์ฝ์ํด์ ์ฌ์ฉํ์ผ๋ฉฐ, true์ผ ๋๋ง ๋๋ฌธ์๋ฅผ ์ฌ์ฉํด์ ๋ค์ฏ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ํ๋์ string์ผ๋ก ๋ฐํํ๋ ํจ์๋ฅผ ์ ์ธํด์ ์ฌ์ฉํ๋ค
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class TemperatureControlTest {
// ๊ฐ์ : hw๋ ์์คํ
์ํ๋ฅผ ๋ํ๋ด๋ ๊ฐ์ฒด
private Hardware hw = new Hardware();
@Test
public void turnOnCoolerAndBlowerIfTooHot() throws Exception {
tooHot(); // ๋๋ฌด ๋จ๊ฑฐ์ด ์ํ๋ฅผ ์๋ฎฌ๋ ์ด์
assertEquals("hBChl", hw.getState());
}
@Test
public void turnOnHeaterAndBlowerIfTooCold() throws Exception {
tooCold(); // ๋๋ฌด ์ถ์ด ์ํ๋ฅผ ์๋ฎฌ๋ ์ด์
assertEquals("HBchl", hw.getState());
}
@Test
public void turnOnHiTempAlarmAtThreshold() throws Exception {
wayTooHot(); // ๋๋ฌด ๋จ๊ฑฐ์ด ๊ฒฝ๊ณ๊ฐ ์ํ๋ฅผ ์๋ฎฌ๋ ์ด์
assertEquals("hBCHl", hw.getState());
}
@Test
public void turnOnLoTempAlarmAtThreshold() throws Exception {
wayTooCold(); // ๋๋ฌด ์ถ์ด ๊ฒฝ๊ณ๊ฐ ์ํ๋ฅผ ์๋ฎฌ๋ ์ด์
assertEquals("HBChl", hw.getState());
}
// ํ๋์จ์ด ํด๋์ค (ํ
์คํธ ๋์ ํด๋์ค์ ๋๋ฏธ ๊ตฌํ)
class Hardware {
private String state;
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
}
ํ๋์ ํ ์คํธ ํจ์์ ํ๋์ assert๋ง ์์ฑํ๋ ๊ฒ์ ์งํฅํ๋ผ๊ณ ํ๋ค
@Test
public void testBankAccount() {
BankAccount account = new BankAccount();
// ์์ก ์ด๊ธฐ๊ฐ ํ์ธ
assertEquals(0, account.getBalance());
// ์
๊ธ ํ ์์ก ํ์ธ
account.deposit(100);
assertEquals(100, account.getBalance());
// ์ถ๊ธ ํ ์์ก ํ์ธ
account.withdraw(50);
assertEquals(50, account.getBalance());
}
ํ์ง๋ง ์ด ์ฝ๋์ ๊ฒฝ์ฐ, ์ฌ๋ฌ assertEquals๋ฅผ ํฌํจํ๊ณ ์์ด ์ฝ๋๊ฐ ๊ธด ๊ฒฝ์ฐ, ์ด๋ค assert๊ฐ ์คํจํ๋์ง ์ฐพ๊ธฐ๊ฐ ์ด๋ ต๊ณ , ๊ฐ๋ ์ฑ์ด ๋จ์ด์ง ์ ์๋ค
์ฅ์
ํ
์คํธ๊ฐ ๋จ์ผ ๊ฒฐ๋ก ์ ๋ด๋ฆด ์ ์์ด ์ดํดํ๊ธฐ๊ฐ ์ฝ๊ณ , ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ ๋ ์ด๋ ๋ถ๋ถ์ด ์คํจํ๋์ง ๋ช
ํํ ํ์
์ด ๊ฐ๋ฅํ๋ค
๋จ์
ํ
์คํธ๋ฅผ ๋๋ฌด ๋ง์ด ๋ถ๋ฆฌํ๋ฉด ์ค๋ณต ์ฝ๋๊ฐ ๋ง์์ง ์ ์๋ค
๋ฐ๋ผ์ ๋ ๊ฐ์ ํ ์คํธ๋ก ๋ถ๋ฆฌํ๊ณ given-when-then ํจํด์ ํ์ฉํ๋ค!
@Test
public void testGetPageHierarchyAsXml() throws Exception {
givenPages("PageOne", "PageOne.ChildOne", "PageTwo");
whenRequestIsIssued("root", "type:pages");
thenResponseShouldBeXML();
}
@Test
public void testGetPageHierarchyHasRightTags() throws Exception {
givenPages("PageOne", "PageOne.ChildOne", "PageTwo");
whenRequestIsIssued("root", "type:pages");
thenResponseShouldContain(
"<name>PageOne</name>",
"<name>ChildOne</name>",
"<name>PageTwo</name>"
);
}
๊ฐ์ฅ ์ข์ ๋ฃฐ์, ํ ์คํธ๋น ํ๋๋ฅผ ๊ฒ์ฆํ๊ณ ์ ํ๋ค๋ฉด assert๋ฌธ์ด ์ฌ๋ฌ๋ฒ ๋์๋ ok!

์ ์ฝ๋๋ ์๋์ฒ๋ผ ๊ฐ์ ํ ์ ์๋ค
์๋๊ฐ ์ ๋๋ฌ๋๋ ์ด๋ฆ์ผ๋ก ์์ ํ์ฌ ํ
์คํธ ๋ฉ์๋๋ฅผ task๋ง๋ค ๊ฐ๊ฐ ๋ง๋ค์ด์ค๋ค

ํ
์คํธ๋ ๋น ๋ฅด๊ฒ ์๋๋์ด์ผ ํ๋ค
๋๋ฆฌ๋ฉด ์ฌ๋ฌ ๋ฒ ๋๋ ค๋ณผ ์ ์๊ธฐ ๋๋ฌธ!
๋
๋ฆฝ์ฑ์ ๋ณด์ฅํด์ผํ๋ค. ํ์ํ ๊ฒ๋ง ์ํ๋ ์ ์๋๋ก!
ํ
์คํธ๊ฐ ์๋ฃ๊ฐ ๋๋ฉด ์์ํ๋ก ๋๋๋ฆฌ๋ ์์
์ด ๋ฐ๋์ ํ์ํ๋ค! (TearDown)
ํ ์คํธ๋ ํน์ํ ํ๊ฒฝ์ด ์๋๋ผ, ์ํํธ์จ์ด๋ฅผ ์ค์นํ ๋ชจ๋ ํ๊ฒฝ์์ ์๋์ด ๊ฐ๋ฅํด์ผ ํ๋ค. ๋ฒ์ฉ์ฑ ์ค์!
์ ๋ ํ ์คํธ ์ํฐ๋ฅผ ๋๋ฅด๊ณ ๋์๋ถํฐ๋ ์ค๊ฐ์ ์ฌ์ฉ์์๊ฒ input์ ๋ฐ๊ฑฐ๋ ๊ฒฐ๊ณผ๋ฅผ ํ์ผ๋ก ์ ์ฅํด์ ์ฌ์ฉ์๋ณด๊ณ ํ์ธํด๋ณด๋ผ๋ ์ก์ ์ด ๋์ค๋ฉด ์๋๋ค
๋ชจ๋ ๊ฒ ๋ค ์๋ํ ๋์ด์ผ ํ๋ค
ํ
์คํธ๋ฅผ ์์ฑํ๋ ์์ ์ด ์ค์ํ๋ค!
TDD! test lag๊ฐ ๋ฐ์ํ๋ฉด ์ฝ๋๊ฐ ์์๊ฐ๊ฒ ๋๋ค
์ฝ๋ฉ์ ํ๊ธฐ ์ ์ ํ ์คํธ๋ฅผ ๋จผ์ ์์ฑ์ ํ๋๊ฐ, ํ ์คํธ๊ฐ ์ฝ๋ฉ์ ๋ฐ๋ผ๊ฐ๋๋ก ๋ฐ๋์ ์ค์ ์ ํด์ผํ๋ค
๊ฐ๋
์ฑ ์ค์!
์ ์ฐ์ฑ, ์ง์๊ฐ๋ฅ์ฑ, ์ฌ์ฌ์ฉ์ฑ!