Instantly share code notes and snippets. Go to capybaranodeactions and here it lists how you can attach a file check a checkbox choose a radio button click a button click a link click a link or a button fill in a text box field select a dropdown uncheck a checkbox or unselect a dropdown. RSpec is a mature, feature-packed testing framework, but the documentation can be difficult to navigate. The official documentation is written as a set of Cucumber tests within Relish. It’s very comprehensive, but also quite sparse, and Cucumber tests are kind of unnatural to read. RSpec Quick Reference 1. Rspec Cheat Sheet loads the file tested by the spec describe ClassName do require 'thing'. describe declares what is being tested and defines a context describe Thing do. Optionally, you can specify before do some code to run before each @thing = Thing.new example. RSpec.describe User, type:. Kotlin Collection Functions Cheat Sheet. Elye in Mobile App Development Publication. Flutter + Source Generation. Raef Mousheimish in Flutter Community. RSpec is a mature, feature-packed testing framework, but the documentation can be difficult to navigate. The official documentation is written as a set of Cucumber tests within Relish. It’s very comprehensive, but also quite sparse, and Cucumber tests are kind of unnatural to read.
When it comes to testing your Chef cookbooks, currently there seem to be two tools that build the standard in the Chef community: ChefSpec and Test Kitchen (with Serverspec, which is the third tool). Where Serverspec can be used for an outside-in testing approach for your infrastructure, ChefSpec is more like unit testing or input testing for your Chef cookbooks. In this blogpost I’ll try to provide some best practices and snippets for common use cases.
ChefSpec’s goal is to simulate a convergence run of Chef in-memory and test expected behavior against this in-memory results. Due to only converging the node in-memory, it provides fast feedback thus making an ideal test framework for a commit stage in a Continuous Integration pipeline for your cookbooks.
ChefSpec Setup
Let’s assume you have a cookbook structure like this:
In order to use ChefSpec in your cookbook, make sure to add it to your Gemfile
After you created your Gemfile
, run bundle install
to install all dependencies.
The spec_helper.rb
configures the rspec framework and looks like this:
All you have to do to run ChefSpec is to go to the root of your cookbook and run rspec
:
Writing your first Spec
Given the following recipe that you want to write a spec for:
here’s how this spec might look like:
In line 3 we open a describe
block for the recipe under test (app_virtualbox::default
). Line 7 simulates the Chef run - in memory, as I described before - and “overrides” a few node attributes that we’ll use in our specs later.
Line 14 shows how we can assert that resources have been invoked by our Chef run. The add_apt_package
method is a so-called matcher, which is defined for every resource that ships with Chef in the ChefSpec framework (see the extensive example folder on Github for a complete list of default matchers and their usage). Additional matchers can either be defined in your own cookbooks or community cookbooks or can be added to your specs for those cookbooks, which do not define their own matchers as we’ll see later.
Using the with
method in line 114, you can further specify the attributes that you want the resource to be called with.
Running this spec, the output will look like this (given you use the parameters -f d -c
when calling rspec
):
“Advanced” Use Cases
Mocking Recipe Inclusion
Let’s say you have a recipe that includes two other recipes:
and you want to test whether your recipe includes the expected recipes (and only those), then you can use the following spec to do this:
Mocking Data Bags
If your recipe under test uses a data bag:
you can mock them as well:
Mocking Shell Commands (e.g. for not_if
conditions)
Given you use a shell command in a not_if
attribute in your resource:
and you want to stub this command to either return true or false in your spec, use this snippet:
Mocking File.exists?
and IO.read
Let’s assume, you want to test a recipe like this:
Therefore, you have to figure out, how to mock a call to File.exists?
and IO.read
in order to mock out the behavior and check whether an exception is raised in the expected circumstances. You can do that with this before
block:
Notifications to other resources
Let’s assume we have a service resource for the Apache server like this
and another resource that writes a configuration file, which should effect a restart of the Apache server
then you can use the following Chefspec test to check whether the notification happens:
Testing for raised exceptions during Chef run
Assume you have a recipe code like this:
Then you can check for the exception being raised in your Chef run using
Write Custom Matchers
If you are using a 3rd-party cookbook that does not provide a matcher for a resource defined within this cookbook, you can write your own matcher. Let’s say you have this resource in your recipe (it actually doesn’t provide a matcher!):
then you can write a matcher ssh_known_hosts_entry_matcher.rb
file like this:
and include it in your spec_helper.rb
like that:
If you have several matchers that you have to implement on your own, you might come up with a folder structure like this:
and you can use the following snippet in your spec_helper.rb
to include those matchers:
Using ChefSpec with Berkshelf
In case you are using Berkshelf for cookbook dependency management, simply add the following line to your spec_helper.rb
:
ChefSpec will then automatically resolve cookbook dependencies for you.
Test Coverage
The following snippet in your spec_helper.rb
file will switch test coverage on:
In your rspec output you will then find something like this:
The .rspec File
You can add a file .rspec
in your cookbook’s root directory that holds a default configuration for your rspec test runs:
this will result in a colored output with the decriptions in the describe
and it
blocks rendered as output on the shell.
Rake Helper Task
A simple Rake task can help you to run all ChefSpec tests in a subdirectory at once. Let’s assume that your coobooks are stored in a subfolder cookbooks
:
Further Resources
RSpec hierarchy
example group > nested group > example > expectations
Example group
basic format for describe or context
Example
it 'a string, or a Class goes here' doend
Expectations
Example has four main parts
expect, an argument to expect, the method .to, and an argument to .toexpect(Car.colors).to match_array(c)
basic format for expectexpect(something).to(something)expect(something).not_to(something)
Describe string syntax
describe '.colors' do #for class methods use this syntaxdescribe '#full_name' do #for instance methods use this syntax
Basic Example format
Format with Documentation
add -f d to command for format documenation example: rspec spec/car_spec.rb -f d
Pending Tests
Rspec Cheat Sheet Pdf
Either omit the do end block or use pending inside the block
Skipping
Use xdescribe or xit or skip inside the block
Fundamentals
One expectation per example because you will only see first failure
Matchers
Used as arguments to .to()Expectations are the statements, matchers provide the variety and complexity
Types
Equivalence matchers, Truthiness matchers, Numeric-comparison matchers, Collection matchers, Observation matchers, and each one allows us to different kinds of things
Equivalence
expect(x).to eq(1) #most common expect(x).to be 1 #same thing as above
Truthiness Matchers
expect(1 < 2).to be(true)expect('some string').to be_truthy #or be_falsy
Numeric Comparison Matchers
expect(100).to eq(100)expect(100).to be 100
Collection Matchers - Arrays, Hashes, Strings
arr = [1,2,3]expect(arr).to match_array([3,2,1]) #in any orderexpect(arr).to contain_exactly(3,2,1)
hash = {:city => 'Dallas', :state => 'TX'}expect(hash).to include(:city) expect(hash).to include(:city => 'Dallas')
Other Matchers
the Regular Expression matcher, the Object Type Matchers, Respond To Matcher, Attribute Matcher, and Satisfy Matcher.
Predicate Matchers - dynamically defined
arr.nil? or arr.odd? or arr.be_even? etcexpect(value).to be_nil / be_odd / be_even / be_integer etc.
useful for custom methods, with a ? such as
arr.visible?where visible is a function below....visible?(x) do ... end.to be_visible
Observation Matchers
Uses a block instead of an argumentexpect {}.to()
array = []expect { array << 1 }.to change(arr, :empty?).from(true).to(false)
another example
expect do bob.first_name = 'Robert' bob.last_name = 'Smith'end.to change(bob, :full_name).from('Bob Smith').to('Robert Smith')
Observe Output
Not really useful for Ruby on Railsexpect {}.to output.to_stdout
Complex Expectations
Complex Expectations uses and, or.and &.or |
Composing Matcher
Rspec Matchers Cheat Sheet
matchers that accept other matchers