Using Ruby Metaprogramming to Output Timestamped Kibana Logs in Your RSpec Tests
At ITV, we verify the behaviour of our Scala micro-service API using core Ruby and RSpec. In order to Continuously Deliver changes to each micro-service, we test individual commits (forming a “candidate service”) in isolation against its proven stable counterparts (from prior runs of this very process).
Consequently, test failures can usually be narrowed down to a failure in an individual micro-service or in the contract between two or more micro-services.
As we use Logstash/Kibana across our environments, we can supplement test failures with a holistic view of the system when those failures occurred.
Of course we only want to see the Kibana logs that encompasses the failed test (and all relevant hooks), otherwise we’ll just be dealing with noise.
In order to solve our problem, we need to do the following:
- Initialise a variable with the time before the entire test suite begins.
- Update the variable after each individual test (so that all
beforetest hooks are taken into account).
- Use the variable defined in (1) if it’s the very first test that fails or (2) if it’s for any test afterwards.
before(:suite) hook - which, as the name implies, runs once before your entire suite of tests -
does not allow instance variables defined in that scope to be used in your tests.
How about a class variable instead?
This now works but will result in Ruby runtime warnings every time the class variable is accessed:
So not the ideal solution.
Instead, using Ruby metaprogramming and class_variable_set we can modify a variable that holds a timestamp in a class that hasn’t been created yet.
When we do need to create an instance of this class (i.e. when we get a test failure), it will be initialised with the
timestamp from the last
after hook (or from the intial
before(:suite) hook if the very first test fails):
Alternatively, you can change
start_time to be a class method instead:
Which means that you can use
start_time directly on the
GlobalDateTime class, rather than creating a new instance
Commentscomments powered by Disqus