DEV Community

Yassu
Yassu

Posted on

Make your RSpec codes HALF. Introduction of RSpecZ extending RSpec for reviewers and developers.

I talked at Omotesando.rb(Ruby meetup in Japan) on the other day.
Surprisingly, Matz attended on that meetup.

At there, Matz give a comment to RSpecZ, a gem for RSpec.
"You should make a Pull Request in RSpec repository."

I didn't make Pull Request yet.
But I noticed that a lot of people are interesting to RSpecZ.
So, I introduce RSpecZ here first.

What is RSpecZ?

RSpec has a big problem.

RSpec codes are Long (means Hard to review).

RSpecZ is trying to solve this problem.
It has methods of extending let, context and subject now.
I want RSpecZ to be a Guide of RSpec in the future so I will make generators, code analyzer and formatter and something like that.

I show you RSpecZ effectiveness with Image.

001

This image is created by applying RSpecZ to a rspec code from a project I participated.

I will tell you how this can be happened.

Basic Features

Extend context

RSpec's context method is flexible and versatilie.
In the other words, it tends to be redundant and hard to understand.

For example,

context 'When phone_number is 090-1234-5678' do
  let(:phone_number) { '090-1234-5678' }
  it { expect(phone.save).to be_truthy }
end
Enter fullscreen mode Exit fullscreen mode

( 090-1234-5678 is valid phone number in Japan.)

This context is redundant. Because context and let show same thing.

But this will be happened very often when we use RSpec.

And one more problem.
RSpec's context has no meaning by itself. context first argument show state of the context.
Without first argument, we cannot know what kind of context it make.

The above code means that set valid phone number to phone_number variable(let).
RSpecZ make this code simple.

set_valid(:phone_number, '090-1234-5678') do
  it { expect(phone.save).to be_truthy }
end
Enter fullscreen mode Exit fullscreen mode

set_valid method combine context and let.
And method name can say valid value will be put to phone_number.

Reviewer can know valid specs will be written in the block when he read the method name.
And lines of code become short.

With RSpecZ you can write multiple valid cases Very Easily.

set_valids(:phone_number, '090-1234-5678', '080-9566-8466', '070-4567-8901', '09045678945' ) do
  it { expect(phone.save).to be_truthy }
end
Enter fullscreen mode Exit fullscreen mode

Same code with RSpec will be

%w[090-1234-5678 080-9566-8466 070-4567-8901 09045678945].each do |phone_number|
  context "When phone_number is #{phone_number}" do
    let(:phone_number) { phone_number }
    it { expect(phone.save).to be_truthy }
  end
end
Enter fullscreen mode Exit fullscreen mode

You can know how easy to review RSpecZ codes with comparing these codes.

RSpecZ has not only set_valid but also set_invalid for case of invalid value set.

Choose correct method to help reviewer review codes.

Extend let

When you write RSpec, you may write this kind of codes,

let(:name) { 'test-name' }
let(:phone_number) { '090-1234-5678' }
let(:address) { 'test-address' }
let(:params) { {
  name: name,
  phone_number: phone_number,
  address: address
} }

subject { get '/api/test', params: params }
Enter fullscreen mode Exit fullscreen mode

This let s can help you to change a part of context from default value.
You can write flexible specs.

However, this codes are also redundant.

RSpecZ has create_params method.

let(:name) { 'test-name' }
let(:phone_number) { '090-1234-5678' }
let(:address) { 'test-address' }
create_params :name, :phone_number, :address

subject { get '/api/test', params: params }
Enter fullscreen mode Exit fullscreen mode

This code has same meaning.
create_params define params let with using defined let s.

Actually, create_params define let with test-xxx characters if the param is not defined yet.
So, below code also has same meaning.

let(:phone_number) { '090-1234-5678' }
create_params :name, :phone_number, :address

subject { get '/api/test', params: params }
Enter fullscreen mode Exit fullscreen mode

I will implement more useful let methods in the future.

Other features

RSpecZ has some other useful methods.
Please check github repository if you are interested.

https://github.com/RSpecZ/RSpecZ

Mesurement effectiveness of RSpecZ

I check the effectiveness of RSpecZ with compare projects.
One is a rails project without RSpecZ (I participate before) and the other one is a rails project with RSpecZ (I currently participate).

Premises

  • These projects are completely different. They has different business logics.
  • I developed code base of both of projects. ( Basic code styles are same)
  • Project with RSpecZ is just started(3 months) so codes are less.
  • We use other features in project with RSpecZ which RSpecZ not yet have. So, not only RSpecZ feature make codes shorter.

Results

Lines of RSpec Num of tests
Project with RSpecZ 2183 1223
Project without RSpecZ 20023 5143

Lines of RSpec: Total lines of request_spec and support files.
Num of tests: Number of examples.

Conclusion

RSpecZ can make RSpec codes HALF.
(CANNOT compare just RSpecZ features because of Premises)

This is may not accurate but we can know the power of RSpecZ from result.

At last

This article introduce RSpecZ features.

RSpecZ is just started a few months before.
We have very few commiters.

Please give comments if you are interested.

Top comments (1)

Collapse
 
gizipp profile image
Gilang

In contrast, a guy from thoughtbot team with 'telling a story' mindset encourages developer should not afraid to write redundant code as long as it is to make clearer documentation.

But actually it seems interesting and promising. It will be nice and handy be to seeing set_valid, set_invalid, or create_params as part of the default Rspec feature. Hope Rspec or RspecZ future will make test practice easier to understand.