I am new to unit tests and I am curious to improve myself. I have a task where I need to generate hashtag (a codewars kata).
It needs to return false if string is empty or has >= 140 characters. I am leaving the link, if necessary: https://www.codewars.com/kata/52449b062fb80683ec000024/train/ruby
def generateHashtag(str)
arr = str.split.map(&:capitalize)
arr.empty? || arr.join.length >= 140 ? false : '#' arr.join
end
p generateHashtag(" Hello there thanks for trying my Kata") # "#HelloThereThanksForTryingMyKata"
p generateHashtag(" Hello World " ) # "#HelloWorld"
p generateHashtag("" ) # false
p generateHashtag('L' * 140) # false
The code works, but I am interested in writing rspec test correctly. Here what I wrote:
require 'rspec'
require './codewars/5kyu/hashtagGenerator'
describe 'generate hashtag when string length is less that 140' do
before :each do
generateHashtag(" Hello there thanks for trying my Kata").length < 140
end
describe 'adds # to the start' do
it 'removes one space' do
expect(generateHashtag(" Hello there thanks for trying my Kata"))
.to eq("#HelloThereThanksForTryingMyKata")
end
it 'removes more than one space' do
expect(generateHashtag(" Hello World ")).to eq("#HelloWorld")
end
end
describe 'empty string' do
it 'returns false' do
expect(generateHashtag("")).to eq(false)
end
end
end
describe 'more than or equal to 140 characters' do
it 'returns false' do
expect(generateHashtag("L" * 140)).to be(false)
end
end
Tests work. But I want to know your opinion: is it okay? Do I do right when using before
to check if length of the string is < 140? Are there other ways to check length before each block? Sorry if question might sound dumb. I may be overengineering :(
CodePudding user response:
In general, your specs are great. You check two normal cases that have different whitespace patterns that seem to be important to you. And you check two edge cases – an empty input and an input that is too long.
But I see any benefit in checking that the output is shorter than 140 chars before each example. All your examples have hard coded inputs and hard-coded, expected outputs anyway, and therefore you already know that none of them will be longer than 149 chars.
Additionally, I would refactor the specs a bit, for example, but that is certainly opinionated:
require 'rspec'
require './codewars/5kyu/hashtagGenerator'
describe '#generate_hashtag' do
subject(:hashtag) { generate_hashtag(input) }
describe 'with valid input' do
let(:input) { ' Hello there thanks for trying my Kata' }
it 'returns the expected formatted output' do
expect(hashtag).to eq('#HelloThereThanksForTryingMyKata')
end
end
describe 'with input with an unusually amount of whitespace' do
let(:input) { ' Hello World ' }
it 'returns the expected formatted output' do
expect(hashtag).to eq('#HelloWorld')
end
end
describe 'with empty input' do
let(:input) { '' }
it 'returns false' do
expect(hashtag).to be(false)
end
end
describe 'with an input being longer than 139 chars' do
let(:input) { "L" * 140) }
it 'returns false' do
expect(hashtag).to be(false)
end
end
end
Nitpicking: Ruby naming conventions for method names are that they should be written with underscores instead of camel case. Which means Ruby would prefer generate_hashtag
over generateHashtag
. Therefore, I already change the method naming in my above answer.