Make your RSpec codes HALF. Introduction of RSpecZ extending RSpec for reviewers and developers.
Tags: ruby, rspec, rails, gem
Published: 2018-07-16 15:28:02

---
title: Make your RSpec codes HALF. Introduction of RSpecZ extending RSpec for reviewers and developers.
published: true
description: Introduction of RSpecZ Gem. It can make your RSpec codes HALF.
tags: ruby, rspec, rails, gem
---

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](https://thepracticaldev.s3.amazonaws.com/i/0omvjmh853t9rf7b11pp.png)



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
```
( `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
```

`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
```

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
```

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 }
```

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 }
```

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 }
```

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.