theme: apple-basic
layout: intro
highlighter: shiki
lineNumbers: true
앱의 메서드 또는 클래스와 같은 작은 단위의 기능을 검증
로컬 단위 테스트 (Local Unit Test)
계측 단위 테스트 (Instrumented Unit Test)
서로 다른 모듈 또는 클래스 간의 상호작용이 정상적으로 기능하는지를 검증
앱의 전체 화면 또는 여러 모듈에 걸친 사용자 흐름과 같은 큰 부분에 대한 기능 검증을 수행
UI 테스트라 부르기도 함
| Feature | Small | Medium | Large |
|---|---|---|---|
| Network access | No | localhost only | Yes |
| Database | No | Yes | Yes |
| File system access | No | Yes | Yes |
| Use external systems | No | Discouraged | Yes |
| Multiple threads | No | Yes | Yes |
| Sleep statements | No | Yes | Yes |
| System properties | No | Yes | Yes |
| Time limit (seconds) | 60 | 300 | 900+ |
Fast: 단위 테스트는 빨라야 한다.Isolated: 테스트가 다른 테스트 케이스에 의존하지 않아야 한다.Repeatable: 테스트는 실행할 때마다 같은 결과를 만들어야 한다.Self-validating: 테스트 결과는 성공이거나 실패여야 한다. 결과에 대한 해석이 필요해서는 안된다.Timely: 단위 테스트는 기능이 출시된 후에도 언제든 작성할 수 있지만 적절한 시점은 프로덕션 코드를 구현하고 있는 와중에 테스트 코드를 작성하는 것이다.Given: 어떠한 상태하에서When: 어떠한 기능을 실행하면Then: 어떠한 결과가 나와야 한다.@Test
fun x1_multiplyBy2_2() {
// GIVEN
val x = 1
// WHEN
val result = Utils.multipleBy2(x)
// THEN
assertEquals(2, result)
}
실제 구성요소 대신 테스트를 수행하는 객체
xUnit Test Patterns의 저자인 제라드 메스자로스(Gerard Meszaros)가 만든 용어
F.I.R.S.T Principles의 Isolated > 테스트 대상이 의존하는 것을 실제가 아닌 다른 것으로 대체
interface AccountDao {
fun showMember()
}
class DummyAccountDao : AccountDao {
override fun showMember() : List<String> {
// No implementation
}
}
interface AccountDao {
fun showMember()
}
class StubAccountDao : AccountDao {
override fun showMember() : List<String> {
val memberList = listOf("Alice", "Bob")
return memberList
}
}
interface AccountDao {
fun showMember()
}
class SpyAccountDao : AccountDao {
private var callMemberCount = 0
override fun showMember() : List<String> {
val memberList = listOf("Alice", "Bob")
callMemberCount++
return memberList
}
}
interface AccountDb {
fun saveItem(userId: Int, name: String)
fun getItem(userId: Int) : String?
}
class FakeAccountDb : AccountDb {
private var accounts = HashMap<Int, String>()
init {
accounts[0] = "Alice"
accounts[1] = "Bob"
}
override fun saveItem(userId: Int, name: String) {
accounts[userId] = name
}
override fun getItem(userId: Int) : String? {
return accounts[userId]
}
}
class Car(
private val engine: Engine,
private val dashboard: Dashboard
) {
fun start() {
engine.ignite()
dashboard.display()
}
}
class CarTest {
var engineMock: Engine = mock(Engine::class.java)
var dashboardMock: Dashboard = mock(Dashboard::class.java)
@Test
fun start_the_car() {
val car = Car(engineMock, dashboradMock)
car.start()
verify(engineMock).ignite()
verify(dashboardMock).display()
}
}
Assertion의 표현력이 부족한 JUnit의 단점을 메워주는 라이브러리
// JUnit
assertTrue(notificationText.contains("testuser@google.com"));
// AssertJ, Truth
assertThat(notificationText).contains("testuser@google.com");
// Hamcrest
assertThat(notificationText, containsString("testuser@google.com"));
Espresso : 단일 안드로이드 앱의 UI를 테스트하는 프레임워크
Kaspresso : KasperskyLab에서 제작한 안드로이드 앱 UI 테스트 프레임워크
Appium : iOS와 Android를 모두 테스트 할 수 있는 UI 테스트 프레임워크
UI Automator : 복수 앱 간의 UI 기능을 테스트하는 프레임워크
| Artifact | Stable Release |
|---|---|
| annotation | 1.0.0 |
| core | 1.4.0 |
| espresso | 3.4.0 |
| ext.junit | 1.1.3 |
| ext.truth | 1.4.0 |
| monitor | 1.5.0 |
| orchestrator | 1.4.1 |
| runner | 1.4.0 |
| rules | 1.4.0 |
| services | 1.4.1 |
Monkey는 에뮬레이터 또는 장치에서 실행되고 클릭, 터치 또는 제스처와 같은 사용자 이벤트의 의사 무작위 스트림과 여러 시스템 수준 이벤트를 생성
여러가지 옵션을 지정 가능
adb shell monkey [options] <event-count>