Last active
May 6, 2019 03:54
-
-
Save willianbragats/953f9203578d2ad14909be1f3bfb0733 to your computer and use it in GitHub Desktop.
Writing meaninful test cases for (you|everyone)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# WRITING GOOD TESTS FOR (YOU|EVERYONE) using TDD/BDD | |
When I was looking how to program in Python, I've stumbled upon a lot of articles and most of them were mentioning | |
that I should learn it using the TDD approach as well. TDD stands for 'Test-Driven Development'. Not only it helps you | |
to maintain the project if needs improvements in the future, but to others as well. | |
So, I've learned the Python basics and at the same time, I was implementing TDD. Some programmers ask you to first | |
create the test case file (in our case with Ruby and Puppet, the 'spec/*/*_spec.rb' file), create the tests cases, run | |
those tests cases (they will fail naturally because you didn't put any code yet) and judging from what you want to achieve, | |
you finally create your code to solve the tests cases and thus implement the feature your code would solve it. | |
I would say it's hard to really implement TDD, but at least gave me an elucidation about testing your code and help | |
everyone how to write code and tests that can be easily maintained. That's the most important lesson that I learned. | |
Recently, I came across an issue where one of the puppet classes were not being tested and I was talking to @dki about | |
test cases using rspec-puppet, and I saw some tests cases they would either start with a 'context' or 'describe' block. | |
We couldn't tell what is the difference between those two, aside from that both ways works. Then I've googled about it | |
and I found this link below. It's a really worth read it and I really recommend you to read it, it will enlight you for | |
the next part of my story. | |
http://lmws.net/describe-vs-context-in-rspec | |
So, the next phase happened when I had created my first test case with rspec. In my first try, I've done it partially | |
using coding style and few of the rspec DSL guidelines. Why? Because that's how I've learned testing with python, using | |
both 'unittest' modules and 'pytest' module. You have to do your tests in a raw way (NOTE: In ruby, we have the 'Test::Unit'). | |
When Kiss evaluated my code and pointed out the odds of how my tests were being done, they were in a very opposite | |
direction of what rspec test cases is supposed to be. rspec is like puppet, a pure DSL for you to run your tests. While | |
using pure Ruby could achieve the same results, we might be writing a hard-to-maintain rspec code. I agree with that. | |
So I just realize that I should learn how to write good rspecs (Not only the rspec-puppet because this is just a rspec | |
module). So I came into this article: | |
https://metaredux.com/posts/2019/04/26/rspec-style-guide-reloaded.html | |
From that article, the most important thing was the rspec style guide, because there is a discussion which guideline is the | |
best to follow. The most recent one that's being maintaned is this one below: | |
https://github.com/rubocop-hq/rspec-style-guide | |
This article eluced me in a following point of the purpose of testing your code with RSPEC: What are you trying to | |
accomplish with your code using the rspec DSL. | |
With that in mind, most of code right now lacks an explanation into the 'it does' block. Usually it is something like this: | |
---- BEGIN: code ---- | |
describe "postgres_mode => master" do | |
profile_environment("truebn_db") | |
it do | |
should compile.with_all_deps | |
should contain_class("profile::db::postgresql_95") | |
should contain_profile__db__postgresql_monitored("truebn-db") | |
should contain_profile__db__postgresql_ssl_access("eventstore") | |
.with(db_name: "eventstore") | |
.with(db_user: "truebn") | |
.with(postgres_mode: "master") | |
end | |
end | |
---- END: code ---- | |
Ok, so it describes a scenario that's called when postgres_mode is set to master, but it doesn't tell us what | |
'it should do' (or what are we asserting) in this case. Just because the 'it block' it's empty. | |
To be clear, we can run rspec specifying the ouput (something I've been using after refactoring my rspec test case). | |
---- BEGIN: shell ---- | |
$ rspec -f d spec/classes/profile/db/truebn_spec.rb | |
profile::db::truebn_db | |
compile | |
should compile into a catalog without dependency cycles | |
should have some resources | |
should contain Profile::Db::Postgresql_ssl_access[eventstore] with db_name => "eventstore" and db_user => "truebn" | |
postgres_mode => master | |
should contain Profile::Db::Postgresql_ssl_access[eventstore] with db_name => "eventstore", db_user => "truebn" and postgres_mode => "master" | |
---- END: shell ---- | |
The point it: Ok, it is testing the class and if the vars are being set normally. But for me, that I am both new to | |
the company and for writing tests with rspec, I don't know what is the purpose of this test. If the test breaks, I have | |
to look into the code (and other modules as well) and trying to analyze what's trying to accomplish it, and after that, | |
I can apply the correct measures. | |
So what we could be simply doing? Explain what "it should do" (and put meaninful contexts). | |
Example: | |
---- BEGIN: code ---- | |
context "with default user and using profile::db::postgresql_95 class to install PostgreSQL 9.5" do | |
profile_environment("profile::db::developer", ["include profile::db::postgresql_95"]) | |
include_examples "common tests" | |
it "creates user porta and sets its pg_hba.conf rule on PostgreSQL 9.5" do | |
should contain_postgresql__server__role("porta") | |
.with(password_hash: "md58da95b22b3a59e5ba5f55994c9064e40") | |
.with(createdb: "true") | |
.with(superuser: "true") | |
.that_requires("Service[postgresqld]") | |
should contain_postgresql__server__pg_hba_rule("allow all access") | |
.with(user: "porta") | |
end | |
end | |
---- END: code ---- | |
And then we can see this happening: | |
---- BEGIN: Shell ---- | |
$ rspec -f d spec/classes/profile/db/developer_spec.rb | |
profile::db::developer | |
with default user and using profile::db::postgresql_95 class to install PostgreSQL 9.5 | |
checks if the catalog compiles and the presence of common resources are applied | |
creates user porta and sets its pg_hba.conf rule on PostgreSQL 9.5 | |
---- END: Shell ---- | |
See the diference? It not only tests our code, but tells us the context of the text. With that in mind, if we are changing | |
a common role that would break multiple rspec tests cases, we can check what are the purposes of those tests and then we | |
can work with that in mind. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment