[안드로이드스튜디오_문화][구글이 써보고 개추한 테스트 코드 작성 방법-1]

기말 지하기포·2024년 1월 13일
0

#Android Test 공식 문서
=>d.android.com/training/testing

#Google Testing Blog
=>https://testing.googleblog.com

대원칙 : 테스트 불변성

-테스트는 변경되어서는 안된다. 작업이 변경되거나 기능이 변경되지 않고 어떤 코드의 재배치 같은 게 일어나거나 새로운 기능이 추가됐다든가 기존에 있는 것들과 연관성이 없는 것들이 추가됐다든가 버그가 수정됐다든가 하는 이유들로 인해서 테스트 코드가 변경되어서는 안된다는 것이 테스트 불변성의 원칙이다. 이로인해 테스트 코드는 코드 변경이 일어나도 신뢰할 수 있는 검증 수단으로서의 역할을 할 수 있다. 예를들면은 아까까지는 테스트가 잘 이루어졌는데 갑자기 원래 코드의 다른 기능을 수정했을 때 테스트 코드가 실행되지 않는다면(이런 것들을 깨지기 쉬운 테스트라고 부른다) 테스트 불변성의 원칙에 어긋난 것이다. 만약 테스트 불변성을 잘 지켰다면 새로운 기능이 추가되도 테스트 코드의 실행에 정상적으로 수행 될 것이다.

구글이 개추한 테스트 코드 작성_1

Pubilc API를 통해서만 테스트 하여라.

-위의 문장이 의미하는 것은 테스트 코든느 대상 API의 사용자와 동일한 조건에서 테스트를 해야된다는 것이다. 즉, 개발자가 자기가 작성하나 코드를 테스트 할 때 외부에서 접근이 가능한 Public API를 통해서만 테스트를 수행하라는 것이다. 따라서 반드시 Public Method만 호출해야 한다.

-테스트 코드에서 사용하고 싶어서 private/protected 메서드를 public으로 변경해서 불러오면 안된다. 왜냐하면 원래 작성된 코드가 지니는 의미를 깨트리기 때문이다.

구글이 개추한 테스트 코드 작성_2

상호작용을 테스트하지말고 상태를 테스트해라

-어떤 테스트가 하나 있을 때 이 테스트의 결과를 보았을 때 테스트가 수행된 이후 상태가 어떻게 변경되었는지를 보고 테스트의 검증이 이루어져야한다. 만약 이렇게 하는 것이 아니라 또 다른 조작을 해서 테스트의 검증이 이루어지면안된다. 즉, 내가 머릿속에서 이미 테스트의 검증결과를 정해놓고 해당 결과가 나오지 않는다고 다른 헛짓거리를 하면 안된다는 의미이다.

-쉽게말하면 테스트의 대상A를 테스트 코드에서 사용했는데 만약 A에 변경이 생긴다면 테스트 코드 자체에 이상이 없는데도 테스트가 실패가 나올 수 있으니까 조심하라는 것이다. 예를들면, 데이터베이스에 풋을 했을 때 동일한 데이터를 넣었을 때 기존에는 그냥 조용히 실패하는것이였는데 해당 코드를 변경하여 예외가 발생하도록 코드를 변경하었다면 테스트 코드는 이상이 없는데도 실패한 테스트가 된다.

-정리하자면, 테스트 코드 작성과 검증 과정에서 중요한것은 테스트가 완료 된 후에 나온 실행 결과가

  • 나쁜 테스트코드 예시코드
  • 아래 코드처럼 함수(상호자용)를 통해서 검증을 하면 안된다.
@Test
fun shouldCreateUsers() {
	accounts.createUser("footbar")
    verify(database).put("footbar")
}

-그러니까 아래와 같은 테스트 코드를 작성해줘야 한다.

  • 아래 코드처럼 상태를 통해서 테스트 코드를 검증해야 한다.
@Test
fun shouldCreateUsers() {
	accounts.createUser("footbar")
    assertThat(accounts.getUser("footbar")).isNotNull()
}

구글이 개추한 테스트 코드 작성_3

테스트 코드를 간결하고 완결성있게 만들어라

완결성

-테스트 코드는, 테스트하고자 하는 것을 정학히 알 수 있는 정보를 모두 갖고 있어야한다. : 완결성

  • 테스트는 전부 다 가지고 있어야 된다. 즉, 테스트 케이스 내부에는 테스트하고자 하는 것을 정확히 알 수 있는 정보를 모두 갖고 있어야 된다. 테스트 케이스 하나만 보았을 때 테스트 케이스 내부에 있는 특정 함수나 어떤 조건들이 뭐지?라는 생각이 머릿속에 들면 안되고 기본적인 조건들이 테스트 케이스 내부에 들어있어야 된다. 또한, 어떤 것을 테스트 하는지 명확하게 작성되있어야 한다. 따라서 테스트 코드를 보았을 때 어떤 조건으로 이 함수를 실행하면 뭐가 나오는지 정확하게 알 수 있어야 된다는 의미이다.

간결성

-테스트 코드는 불필요한 내용은 감춰야 한다. : 간결성

-완결성을 위한 정보들을 제외한 모든 불필요한 내용들은 감춰야 된다. 예를 들어 어떤 객체를 하나 만들기 위해서 parameter가 20개가 필요한데 실제로 해당 테스트코드와 연관된 것은 5개밖에 없다면 나머지 15개를 수단과 방법을 가리지 않고 감춰야 된다. 최종적으로는 테스트에 관련된 정보들만 필요할 수 있도록 해야된다. 또한, 감춰진 parameter들에 변경이 발생하더라도 테스트 코드에는 영향을 미치면 안된다. 이로서 테스트의 가독성을 높인다.

  • 나쁜 예시코드(1)
  • 아래코드를 보면 테스의 조건이 뭔지도 모르고 5가 갑자기 어디서 튀어나왔는지도 몰그겠고 뭐라는건지 모르겠어.
@Test
fun shouldPerformAddition() {
	val calculator = Calculator(RoundingStrategy(),
    "unused" , ENABLE_COSINE_FEATURE, 0.01 , calculusEngine , false)
    
    val result = calculator.calculate(newTestCalculation())
    assertThat(result).isEqualTo(5)
}
  • 좋은 예시코드(2)
  • newCalculator라는 헬퍼함수를 만들어서 내부에서는 Calculator의 생성자를 호출을 하지만 여기에서 관련이 없는 것들은 다 빼놓도록 한다.
  • 또한 calculator 안에도 newCalculation이라고 하는 헬퍼 함수를 만들어서 나쁜코드에서의 newTestCalculation()의 의미를 알 수 있도록 그래서 2가 있고 operation의 place가 있고 3이 있고 그래서 2+3이 라는 것을 명백히 알 수 있게 해준다. -> 여기서 "완결성"부여!
  • 덧셈이 제대로 동작하는지를 테스트한다는 의미에서 그것과 관계없는 것은 모두 다 감춰져 있다.
@Test
fun shouldPerformAddition() {
	val calculator = newCalculator()
    val result = calculator.calculate(newCalculation(2 , Operation.PLUS , 3))
    assertThat(result).isEqualTo(5)
}
profile
포기하지 말기

0개의 댓글