I had been working on a new micro-service in a newly joined team. Once basic functionality was ready and I got some breathing time, I thought I would look for any technical debt that I have accrued. During this, I got to know that the team has already been using Sonar for statistical analysis of the code.
When I checked the project’s sonar status, I got to know many smells, debt and issues that I would need to fix. One of them was about naming the test methods. The rule configured was expecting test method name to follow
Basically test name should start with test word.
How I had been using was like
twoPlusTwoEqualsFour. So to fix these apparent code smells, I had to rename around 230 methods to follow expected pattern.
twoPlusTwoEqualsFour to become
I would have let it go and follow the naming convention for new tests I write. But that would cause me many sleepless nights knowing those smells exist there, which I can fix but chose not to.
I could have manually done it or have checked if that can be done with IntelliJ editor. But the automation freak that I am, I decided to do it with few linux commands.
I knew it would take more time to figure out the commands, but you know the compulsive disorder, couldn’t beat it.
Stepwise what I had to was :
- Find methods annotated with
- Rename methods by capitalizing first letter and pre-pending
Final command I used was
Stepwise explanation goes like this:
grep -r -A1 –include=*Test.java “@Test”
Using grep command to find methods annotated with
- -r : to recursively find match in all files in current directory
- -A1 : Include line 1 after the matching line, there exists -C and -B like -A.
- –include : flag to include only Test classes
Partial output was:
grep -v @Test
Using -v option to remove the lines matching the word. Result was:
grep -v test
Remove methods which already has test in the name
To remove line
-- and include only the line with method name
It is done to for resulting line to have file location required for next commands.
cut -d’ ‘ -f5,1
To break the lines by delimiter ‘ ‘ (space)
- -d : Specify delimiter that is space.
- -f : to pick up 1st and 5th column of split text
Due to double space between file name and public word, columns I had to pick were 1,5. Result was:
xargs is used to build arguments for commands that follows. Option -n is for number of arguments.
A command that is passed to
xargs would have argument in variables coming from result of previous command.
- $0 : src/test/java/com/org/project/name/util/TestClass.java
- $1 : twoPlusTwoEqualsFour()
sh -c ‘cmd’
Command used to run a command ‘cmd’, allows to build cmd at runtime
sed -i “s/$1/test\u&/g” $0
Here $0 would be replaced by method name and $1 by file path, so the command run is
sed -i “s/twoPlusTwoEqualsFour()/test\u&/g” src/test/java/com/org/project/name/util/TestClass.java
Now this is some complex command. This is sed (Stream Editor) command generally used to process and replace text in files.
Meaning of options as
- -i : Replace content in file itself (in-place), other related options are to print changed content without making actual changes or to make changes while creating backup file.
- $0 : coming from xargs is a file to edit
s/$1/test\u&/g: this means find content matching $1(twoPlusTwoEqualsFour(), method name) and replace it with
&means matched content(twoPlusTwoEqualsFour()) \u does upper case next character.
So it would replace
testTwoPlusTwoEqualsFour() which is what we want.
Due to magic of pipe, these commands get applied to all the matching methods in the directory.
Hurray! I did rename all the methods with few commands (taking more time than if it had been done manually).
Had I done it manually though, I probably wouldn’t have learnt these commands in a little more details.
Next time I need to do something similar, I would do it faster (may be).
Hope this it at-least helped you.