Ruby comes with Coverage, a simple standard library for test coverage measurement for a long time.
Before Ruby 2.5
Before Ruby 2.5,
we could measure just the line coverage using
Line coverage tells us whether a line is executed or not. If executed, then how many times that line was executed.
We have a file called
Now create another file
to measure the coverage of
Coverage#result returns the coverage result.
Let’s run it with Ruby 2.4.
Let’s look at the output.
Each value in the array
[1, nil, 1, 0, nil, 1, nil]
denotes the count of line executions by the interpreter
for each line in
This array is also called the “line coverage”
nil value in line coverage array means
coverage is disabled for that particular line number
or it is not a relevant line.
end and blank lines
have line coverage disabled.
Here’s how we can read above line coverage result.
- Line number 1 (i.e. 0th index in the above result array) was executed once.
- Coverage was disabled for line number 2 (i.e. index 1) as it is blank.
- Line number 3 (i.e. index 2) was executed once.
- Line number 4 did not execute.
- Coverage was disabled for line number 5 as it contains only
- Line number 6 was executed once.
- Coverage was disabled for line number 7 as it contains just
After Ruby 2.5
There was a pull request opened in 2014 to add method coverage and decision coverage metrics in Ruby. It was rejected by Yusuke Endoh as he saw some issues with it and mentioned that he was also working on a similar implementation.
In Ruby 2.5,
Yusuke Endoh added branch coverage and method coverage feature
Let’s see what’s changed in
Coverage library in Ruby 2.5.
If we execute above example using Ruby 2.5, we will see no change in the result.
This behavior is maintained
to ensure that the
stays 100% backward compatible.
If we explicitly enable
in the above
the coverage result will be different now.
We can see that the coverage result is now a hash
which reads that the
lines coverage as
[1, nil, 1, 0, nil, 1, nil].
Branch coverage helps us identify which branches are executed and which ones are not executed.
Let’s see how to get branch coverage.
We will update the
Here is how to read the data in array.
[ BRANCH_TYPE, UNIQUE_ID, START_LINE_NUMBER, START_COLUMN_NUMBER, END_LINE_NUMBER, END_COLUMN_NUMBER ]
Please note that column numbers start from 0 and line numbers start from 1.
Let’s try to read above printed branch coverage result.
[:if, 0, 3, 0, 7, 3] reads that
starts at line 3 & column 0
ends at line 7 & column 3.
[:then, 1, 4, 2, 4, 15] reads that
starts at line 4 & column 2
ends at line 4 & column 15.
[:else, 2, 6, 2, 6, 15] reads that
starts at line 6 & column 2
ends at line 6 & column 15.
as per the branch coverage format,
we can see that
the branch from
then was never executed
The another branch from
else was executed once
Measuring method coverage helps us identify which methods were invoked and which were not.
We have a file
To measure method coverage of above file,
Let’s run it using Ruby 2.5.
The format of method coverage result is defined as shown below.
[ CLASS_NAME, METHOD_NAME, START_LINE_NUMBER, START_COLUMN_NUMBER, END_LINE_NUMBER, END_COLUMN_NUMBER ]
[Object, :grade, 9, 0, 17, 3] => 3
reads that the
which starts from line 9 & column 0
line 17 & column 3
was invoked 3 times.
We can measure all coverages at once also.
What’s the use of these different types of coverages anyway?
Well, one use case is to integrate this in a test suite and to determine which lines, branches and methods are executed and which ones are not executed by the test. Further, we can sum up these and evaluate total coverage of a test suite.
Author of this feature, Yusuke Endoh (mame)
has released coverage-helpers gem
which allows further advanced manipulation and processing of
coverage results obtained using