오늘도 삽질중

클린코드 책을 읽고서 Chapter. 단위테스트 with. TDD 본문

기타

클린코드 책을 읽고서 Chapter. 단위테스트 with. TDD

Choi3950 2020. 12. 17. 12:47
반응형

본 포스팅은 개인정리 목적으로 작성된 글입니다.

잘못된 정보가 있을 수 있으며, 피드백은 겸허히 받겠습니다.


해당 챕터를 읽고 인지하면 좋을만한 내용을 간단하게 정리해 봤다.



TDD의 법칙 3가지

1. 실패하는 단위 테스트를 작성할 때 까지 실제 코드를 작성 하지 않는다.

2. 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.

3. 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.


해당 Flow를 따를 경우 개발과 테스트가 대략 30초 주기로 묶인다.(TDD 작성법이 원할하다고 가정 할 때)




일회용 테스트 코드만 짜다가 자동화된 단위 테스트를 짜기란 쉽지 않다. 둘 사이의 간극은 아주 크다.

테스트코드는 간결하고 명확해야 한다. 

이유는? 지저분한 테스트 코드로 진행을 하는것은 안하는것과 똑같다.

그러므로, 테스트 코드도 실제 코드 못지 않게 깨끗하게 짜야만 한다.




TDD를 진행해야 하는 이유는?

유연성, 유지보수성, 재사용성 을 제공한다.

테스트 케이스가 있다면 변경이 두렵지 않다.

테스트 케이스가 존재하지 않다면 모든 변경은 잠정적인 버그를 내포하고 있다.



깨끗한 테스트 코드를 만들려면 세가지가 필요하다.

가독성!, 가독성!!, 가독성!!!

오히려 실제 코드보다 테스트 코드에 가독성이 훨씬 중요하다.



깨끗한 테스트는 5가지의 규칙을 따른다. 

각 규칙에서 첫글자를 따서 F.I.R.S.T 가 된다.

1. 빠르게 (Fast)

테스트는 빨라야 한다. 테스트가 느리면 자주 돌리지 못하고 그럴 경우 초반에 문제를 찾아내 고치지 못하게 된다.


2. 독립적으로(Independent) 

각 테스트는 서로 의존하면 안 된다. 한 테스트가 다음 테스트가 실행될 환경을 준비해선 안된다.

각 테스트는 독립적으로, 실행순서에 영향을 받아선 안된다.

테스트가 서로 의존하게 되면 하나가 실패하면 연달에 실패하므로 원인 파악이 어려워 진다.


3. 반복가능하게(Repeatable)

테스트는 어떤 환경에서도 반복이 가능해야 한다.


4. 자가검증하는(Self-Validating)

테스트는 Boolean 값으로 결과를 내야 한다. 즉 성공 아니면 실패다.


5. 적시에(Timely)

테스트는 적시에 작성해야 한다.  단위테스트는 테스트하려는 실제 코드를 구현하기 직전에 구현한다.



사실 이 내용만 가지곤 너무 어렵다.

이렇게 된거 아주 조금씩이라도 TDD를 연습해보는게 좋다고 생각했다.

그래서 여러 예제를 보면서 간단하게 작성해 봤다.


app.Level gradle에 의존성 추가

androidTestImplementation fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.android.support.test.espresso:espresso-idling-resource:3.0.2'
implementation 'junit:junit:4.12'

androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'


실제 테스트코드를 적용해 볼 Class 작성

class Calculator {

private var a: Int = 0
private var b: Int = 0


fun add(a: Int, b: Int): Int {
this.a = a
this.b = b
return a + b
}

fun minus(a: Int, b: Int): Int {
this.a = a
this.b = b
return a - b
}


}



테스트 코드 작성

@RunWith(AndroidJUnit4::class)
class TestCalculator {

lateinit var calculator: Calculator

@Before
fun init() {
calculator = Calculator()
}

@Test
fun testAdd() {
val result = calculator.add(10,35)
assertThat(result ,`is`(45) )
}

@Test
fun testMinus() {
val result = calculator.minus(25,10)
assertThat(result ,`is`(15) )
}

}

해당 코드를 실행하면 정상동작 여부판단이 가능하다.

 즉 testAdd() 에서 assertThat(result , `is`(45)) 는 에러없이 정상실행 

assertThat(result , `is`(44)) 는 에러를 뱉게 된다.

이유는 10 + 35 는 45이므로




근데 이런거 말고 난 안드로이드 개발자이다. 액티비티와 뷰를 제어해서 테스트 해볼 수 없을까?

정말 간단하게 버튼을 클릭시켜서 버튼의 텍스트를 바꾸는 코드를 작성해 봤다.

@RunWith(AndroidJUnit4::class)
class TestMainActivity {


@get:Rule
val activityTestRule = ActivityScenarioRule(MainActivity::class.java)

@Before
fun setUp() {
activityTestRule.scenario.onActivity {
it.findViewById<Button>(R.id.btn)?.let {
viewTextChange()
}
}
}

@Test
fun viewTextChange() {
activityTestRule.scenario.onActivity {
it.findViewById<Button>(R.id.btn).text = "45"
it.findViewById<Button>(R.id.down1).text = "Start"
}
}

}

해당 코드를 실행하니 버튼을 클릭하고 자동으로 btn의 텍스트와 down1 의 텍스트를 변경하고 액티비티가 종료되었다.

디테일한 부분은 좀 더 보면서 보완하는게 좋을거 같다.


반응형
Comments