Coverage 모듈

Coverage 모듈

Coverage는 Ruby에 커버리지 측정 기능을 제공해요. 이 기능은 실험적이라 API가 앞으로 바뀔 수 있어요.

주의: 현재는 프로세스 전역 커버리지 측정만 지원돼요. 스레드별 커버리지는 측정할 수 없어요.

사용법

  1. require "coverage"
  2. Coverage.start 실행
  3. Ruby 소스 파일을 require하거나 load
  4. Coverage.result는 파일 이름을 키로, 커버리지 배열을 값으로 갖는 해시를 돌려줘요. 커버리지 배열은 각 줄에 대해 인터프리터가 그 줄을 몇 번 실행했는지를 보여줘요. nil 값은 그 줄에 대해 커버리지가 비활성화되었음을 뜻해요(elseend 같은 줄).

예시

[foo.rb]
s = 0
10.times do |x|
  s += x
end

if s == 45
  p :ok
else
  p :ng
end
[EOF]

require "coverage"
Coverage.start
require "foo.rb"
p Coverage.result #=> {"foo.rb"=>[1, 1, 10, nil, nil, 1, 1, nil, 0, nil]}

출처: Ruby 3.3 API

본문

라인 커버리지 (Lines)

커버리지를 시작할 때 커버리지 모드를 명시하지 않으면 라인 커버리지가 실행돼요. 각 줄이 몇 번 실행됐는지를 보고해요.

require "coverage"
Coverage.start(lines: true)
require "foo.rb"
p Coverage.result #=> {"foo.rb"=>{:lines=>[1, 1, 10, nil, nil, 1, 1, nil, 0, nil]}}

라인 커버리지 결과 값은 각 줄이 실행된 횟수를 담은 배열이에요. 이 배열의 순서가 중요해요. 예를 들어 인덱스 0의 첫 항목은 파일 1번 줄이 커버리지 실행 동안 몇 번 실행됐는지를 알려줘요(이 예시에선 1번). nil 값은 커버리지가 비활성화된 줄(else, end 같은)을 뜻해요.

원샷 라인 커버리지 (Oneshot Lines)

원샷 라인 커버리지는 커버리지가 실행되는 동안 실행된 줄을 추적하고 보고해요. 줄이 몇 번 실행되었는지는 알려주지 않고, 실행되었는지 여부만 알려줘요.

require "coverage"
Coverage.start(oneshot_lines: true)
require "foo.rb"
p Coverage.result #=> {"foo.rb"=>{:oneshot_lines=>[1, 2, 3, 6, 7]}}

원샷 라인 커버리지 결과 값은 실행된 줄 번호를 담은 배열이에요.

브랜치 커버리지 (Branches)

브랜치 커버리지는 각 조건문 안의 각 분기가 몇 번 실행됐는지를 보고해요.

require "coverage"
Coverage.start(branches: true)
require "foo.rb"
p Coverage.result #=> {"foo.rb"=>{:branches=>{[:if, 0, 6, 0, 10, 3]=>{[:then, 1, 7, 2, 7, 7]=>1, [:else, 2, 9, 2, 9, 7]=>0}}}}

브랜치 해시의 각 항목은 하나의 조건문이고, 그 값은 그 조건문 안의 각 분기가 담긴 또 다른 해시예요. 값은 메서드가 실행된 횟수이고, 키는 분기를 식별하는 정보예요.

분기나 조건문을 식별하는 키를 이루는 정보는 왼쪽부터 다음과 같아요.

  • 분기·조건문 타입의 라벨
  • 고유 식별자
  • 파일에서 그 부분이 나타나는 시작 줄 번호
  • 파일에서 그 부분이 나타나는 시작 열 번호
  • 파일에서 그 부분이 나타나는 끝 줄 번호
  • 파일에서 그 부분이 나타나는 끝 열 번호

메서드 커버리지 (Methods)

메서드 커버리지는 각 메서드가 몇 번 실행됐는지를 보고해요.

[foo_method.rb]
class Greeter
  def greet
    "welcome!"
  end
end

def hello
  "Hi"
end

hello()
Greeter.new.greet()
[EOF]

require "coverage"
Coverage.start(methods: true)
require "foo_method.rb"
p Coverage.result #=> {"foo_method.rb"=>{:methods=>{[Object, :hello, 7, 0, 9, 3]=>1, [Greeter, :greet, 2, 2, 4, 5]=>1}}}

메서드 해시의 각 항목은 하나의 메서드를 나타내요. 값은 메서드가 실행된 횟수이고, 키는 메서드를 식별하는 정보예요.

메서드를 식별하는 키를 이루는 정보는 왼쪽부터 다음과 같아요.

  • 클래스
  • 메서드 이름
  • 파일에서 메서드가 나타나는 시작 줄 번호
  • 파일에서 메서드가 나타나는 시작 열 번호
  • 파일에서 메서드가 나타나는 끝 줄 번호
  • 파일에서 메서드가 나타나는 끝 열 번호

모든 커버리지 모드 (All)

이 단축키로 모든 커버리지 모드를 동시에 실행할 수도 있어요. 모든 모드를 실행해도 라인 커버리지와 원샷 라인 커버리지는 동시에 실행되지 않아요. 이 두 모드는 동시에 실행할 수 없거든요. 이 경우 라인 커버리지가 실행되는데, 줄이 실행되었는지 여부를 여전히 알 수 있기 때문이에요.

require "coverage"
Coverage.start(:all)
require "foo.rb"
p Coverage.result #=> {"foo.rb"=>{:lines=>[1, 1, 10, nil, nil, 1, 1, nil, 0, nil], :branches=>{[:if, 0, 6, 0, 10, 3]=>{[:then, 1, 7, 2, 7, 7]=>1, [:else, 2, 9, 2, 9, 7]=>0}}, :methods=>{}}}

클래스 메서드

  • line_stub(file) — 파일의 각 줄에 대해 커버리지 값 자리가 마련된 배열을 만들어요.
  • peek_result → hash — 파일 이름을 키로, 커버리지 배열을 값으로 갖는 해시를 돌려줘요. Coverage.result(stop: false, clear: false)와 같아요.
  • result(stop: true, clear: true) → hash — 파일 이름을 키로, 커버리지 배열을 값으로 갖는 해시를 돌려줘요. clear가 true면 카운터를 0으로 지우고, stop이 true면 커버리지 측정을 비활성화해요.
  • resume → nil — 커버리지 측정을 시작/재개해요. 주의: 현재는 프로세스 전역 측정만 지원해서 멀티 스레드 프로세스에서 특정 코드 블록의 커버리지를 잡으려고 Coverage.resume/suspend를 쓰면 결과가 오해를 부를 수 있어요.
  • running? → bool — 커버리지 측정이 현재 진행 중인지(true) 아닌지(false)를 돌려줘요(Coverage.start 호출 후 Coverage.result 호출 전).
  • setup → nil, setup(:all) → nil, setup(lines:bool, branches:bool, methods:bool, eval:bool) → nil, setup(oneshot_lines: true) → nil — 커버리지 측정을 설정해요. 이 메서드는 측정 자체를 시작하지는 않아요. 측정을 시작하려면 Coverage.resume을 쓰세요. 설정과 시작을 함께 하려면 Coverage.start를 쓰면 돼요.
  • start → nil, start(:all) → nil, ... — 커버리지 측정을 활성화해요. Coverage.setupCoverage.resume을 합친 것과 같아요.
  • state → :idle, :suspended, :running — 커버리지 측정의 상태를 돌려줘요.
  • supported?(mode) → true or false — 주어진 모드에 대해 커버리지 측정이 지원되면 true를 돌려줘요. 모드는 :lines, :oneshot_lines, :branches, :methods, :eval 중 하나여야 해요. 예: Coverage.supported?(:lines) #=> true, Coverage.supported?(:all) #=> false
  • suspend → nil — 커버리지 측정을 일시 중지해요. Coverage.resume으로 다시 시작할 수 있어요.