Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save willianbragats/953f9203578d2ad14909be1f3bfb0733 to your computer and use it in GitHub Desktop.
Save willianbragats/953f9203578d2ad14909be1f3bfb0733 to your computer and use it in GitHub Desktop.
Writing meaninful test cases for (you|everyone)
# 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