Assert performance with Rspec benchmark

In the world of Ruby development it’s accepted practice to test your code, but only a few people do performance testing. Such tests help to prevent the program work from slowing down while the amount of data grows, and they also help to understand whether the code performance has become slower after the recent code amendments.

To start writing such tests, you need to add gem 'rspec-benchmark'

https://github.com/piotrmurach/rspec-benchmark


require 'rspec-benchmark'



RSpec.configure do |config|

  config.include RSpec::Benchmark::Matchers

end



def linear_method(size)

  a = []

  size.times { a << nil }

end



def quadratic_method(size)

  a = []

  (size*size).times { a << nil }

end



describe 'Performance' do

  context '#linear_method' do

    it 'works under 1 ms' do

      expect {

        linear_method(500_000)

      }.to perform_under(1).ms.warmup(2).times.sample(10).times

    end



    it 'works faster than 1000 ips' do

      expect {

        linear_method(500_000)

      }.to perform_at_least(1000).within(1).warmup(0.2).ips

    end



    it 'performs linear' do

      expect { |n, _i| linear_method(n) }.to perform_linear.in_range(10, 10_000)

    end

  end



  context '#quadratic_method' do

    it 'performs power' do

      expect { |n, i| quadratic_method(n) }.to perform_power.in_range(10, 10_000)

    end



    it 'peforms slower than linear' do

      expect { quadratic_method(10_000) }.to perform_slower_than { linear_method(10_000) }

    end

  end

end

I’ve created two methods to check the tests’ work: linear_method(size) и quadratic_method(size).

As you can see in the graph, the amount of data doesn’t affect the complexity of the linear function O(n) unlike the quadratic O(n2).

graph




    it 'works under 1 ms' do

      expect {

        linear_method(10_000)

      }.to perform_under(1).ms.warmup(2).times.sample(10).times

    end

This test checks that our method is executed in 1 ms with a data volume of 10_000, as each time you run the test, the data might differ slightly, you can set up the test run, for example, 10 times to get averaged data and run the test 2 times to warm up the code.




    it 'works faster than 1000 ips' do

      expect {

        linear_method(500_000)

      }.to perform_at_least(1000).within(0.2).warmup(warmup_seconds).ips

    end

In addition to checking the execution time you can check for the number of operations per second (ips) and limit the test execution time up to 0.2 seconds.




 it 'performs linear' do

      expect { |n, _i| linear_method(n) }.to perform_linear.in_range(10, 10_000)

    end   

Here is the testing of the method for its linearity O(n) in the range of 10-10000.




 it 'performs power' do

      expect { |n, _i| quadratic_method(n) }.to perform_power.in_range(10, 10_000)

    end

Checking exponentiality of the method, in this case it is the quadratic complexity O(n2).




it 'peforms slower than linear' do

    expect { quadratic_method(500_000) }.to perform_slower_than { linear_method(500_000) }

  end

Also, it’s possible to compare each execution test speed.



I’ve told you only about a small part of the functionality of rspec-benchmark, this gem contains many other matchers and it’s possible to check how many objects were created.

PS: there are tools that help you to profile the code to ensure your assert performance tests always show green, for example, ruby-prof, but we will discuss it some other time.

Happy testing!

Do you have a project for us?Get a free quote