Testing Infrastructure with Test Kitchen and Chef
Tags: azureapril, devops, azure, tutorial
Published: 2019-04-24 08:25:27

---
title: Testing Infrastructure with Test Kitchen and Chef
description: Learn how to test infrastructure with Test Kitchen, Chef, and InSpec on Azure.
published: true
tags: azureapril, devops, azure, tutorial
series: "Azure April"
cover_image: https://thepracticaldev.s3.amazonaws.com/i/pblyvmtj4y8bdqisyzey.jpeg
---

*We've selected our favorite tips and tricks created by [Michael Crump](https://twitter.com/mbcrump) as well as planned fresh technical content on Azure all April! Miss a day (or more)? [Catch up with the series](https://dev.to/t/azureapril/latest).*

**Don't have Azure?** [Grab a free subscription](https://azure.microsoft.com/en-us/free?&WT.mc_id=azureapril_devto-blog-cxa). 

Once I've have a Test Kitchen [configuration](https://dev.to/azure/building-infrastructure-with-test-kitchen-and-chef-5g99) that works I can copy that configuration from project to project modifying what is needed. How do I write tests for the infrastructure that I'm building though?

In this post, I'm going to walk through how to test a sample Node.js project using [InSpec](https://www.inspec.io/), [Test Kitchen](https://kitchen.ci/), and the [kitchen-azurerm driver](https://github.com/test-kitchen/kitchen-azurerm). Everything in this post depends on the work from [Testing Infrastructure with Test Kitchen and Chef on Azure](https://dev.to/azure/building-infrastructure-with-test-kitchen-and-chef-5g99) so if you are trying to replicate these steps make sure to check out that post first. Additionally, Test Kitchen can be configured to work with a variety of provisioners and drivers, so if you use Puppet or Ansible; for example, you can totally use those instead. 

As mentioned in [yesterday's post](https://dev.to/azure/building-infrastructure-with-test-kitchen-and-chef-5g99), I've got the [Chef Development Kit(ChefDK)](https://downloads.chef.io/chefdk) installed on my system which includes [InSpec](https://www.inspec.io/). Towards the end of 2018, Chef [released](https://blog.chef.io/2018/10/16/announcing-general-availability-of-chef-workstation/) the [Chef Workstation](https://downloads.chef.io/chef-workstation/stable) as a replacement for the Chef Development Kit. If you don't have ChefDK, Chef Workstation is a good starting point with the same software included.

Before I get too into the details, the goal of the article is to show InSpec and not the perfect way to write Chef code, especially for this application. For example, there is a [nodejs community cookbook](https://supermarket.chef.io/cookbooks/nodejs) that has a lot more bells and whistles that might provide the necessary functionality for deploying Node.js/npm and managing npm packages. With that said, let's get started! 

## Prerequisites

* [Chef Development Kit(ChefDK)](https://downloads.chef.io/chefdk)
* [Service Principal](https://dev.to/azure/you-gotta-keep-privileges-separated-509)
* ~/.azure/credentials configured with your Service Principal configuration

Revisiting line 14 from the .kitchen.yml file, we can see the configuration _verifier_. 

{% gist https://gist.github.com/iennae/9d3ff96f3787c89990f746ce2238d258 %}

The verifier is what we use to test the infrastructure configuration that we have defined. In this configuration, it's set to inspec, but we can also use [Serverspec](https://serverspec.org/) or [Bats](https://github.com/bats-core/bats-core). 

**Note: It's possible to use InSpec without Test Kitchen, and validate the infrastructure that we've built with [Azure Resource Management templates](https://dev.to/azure/demystifying-arm-templates-azure-resource-manager-b8c) or Terraform as well. Check out all these great [InSpec Azure Resources](https://www.inspec.io/docs/reference/resources/#azure-resources) to validate different parts of your infrastructure!** 

## Describing the Infrastructure Testing Process

I'm going to follow the Red-Green-Refactor cycle in developing my infrastructure code. First, I'll write the test that describes a basic feature I want to add. This test will fail because I haven't written any infrastructure code. This is the "red" or failed phase. Then I'll write the infrastructure code that will make the test pass. This is the "green" or passing phase. Then I'll refactor the code I just wrote to make it better. 

One critical difference in infrastructure coding versus project code is unit tests are generally the first tests and largest number of tests to write as per the [testing pyramid](https://martinfowler.com/articles/practical-test-pyramid.html#TheTestPyramid). In infrastructure coding, unit tests are often written incorrectly and test the infrastructure application. For example, writing a test that a package using default package resources gets installed in the right place. That kind of test belongs in a test suite for Chef or Puppet and not within the infrastructure code. 

Depending on the type of infrastructure unit you are writing, for example with Chef whether it's a cookbook that is a library cookbook versus a wrapper cookbook, you might want to unit test whether a specific file gets created. That's a subtle difference in testing. Testing whether your infrastructure application does the right thing means you are introducing brittleness into your testing suite which makes testing harder as well as more error prone. 

**Is there a reason to write unit tests for infrastructure code?** Sure! Especially when we are writing complex code that needs to exercise different paths. For unit tests with Chef, I'd use [chefspec](https://github.com/chefspec/chefspec). For now, I'm starting with integration tests and using InSpec.

## Implementing a Test

The first thing I would need to get an Express app running is to make sure I have Node.js and npm installed on my node. I use the [command](https://www.inspec.io/docs/reference/resources/command/) resource to validate that Node.js is installed. The command resource allows me to run a specific command on the instance and validate a set of properties. 

Yesterday, when I ran `chef generate cookbook test_software_cookbook` it set up a bunch of scaffolding for me that includes an integration test at `test_software_cookbook/test/integration/default/default_test.rb`. I cleaned up the contents and implemented the first test. 

{% gist https://gist.github.com/iennae/b39a7244c313c0a797808ac5afddf7ca %}

I run `kitchen converge` followed by `kitchen verify`, and I get my expected "red" output because Node.js isn't installed. 

![After running kitchen verify I get the exit_status crossed off as I'm failing the test.](https://thepracticaldev.s3.amazonaws.com/i/4sm71jabiy3y3gk60lg1.png)


## Implementing Passing Infrastructure Code

To install Node.js from the Ubuntu provided repositories, I can use the Chef [package resource](https://docs.chef.io/resource_package.html). 

{% gist https://gist.github.com/iennae/067ecc54c161c4d1de4d98c72e1d6930 %}

**Note: In an enterprise environment, I might have my artifacts cached locally so I'd have a different method of defining this code, but it's sufficient for this example.**

I run `kitchen converge`. This time I can see that my node is getting updated and Node.js is getting installed:

```
       Recipe: test_software_cookbook::default
         * apt_package[nodejs] action install
           - install version 8.10.0~dfsg-2ubuntu0.4 of package nodejs
```

Now when I run `kitchen verify`, I get my expected "green" output because Node.js is installed. 

![After running kitchen verify I get a Test Summary showing in green text 1 successful test and with the exit_status checked off as passing the test.](https://thepracticaldev.s3.amazonaws.com/i/hcqamd6nzt1wsuzjocay.png)

That's an [old version of Node.js](https://nodejs.org/en/download/), but it's what is available with Ubuntu 18.10 default packages.

To refactor, I use the Chef [apt_repository resource](https://docs.chef.io/resource_apt_repository.html) to update where I download updated [binary distributions from NodeSource](https://github.com/nodesource/distributions).

{% gist https://gist.github.com/iennae/c26774c19ebf390d6e5136324127b9e5 %}

During the converge I can see the latest Node.js getting installed from NodeSource 

![Chef converge showing install version 10.15.3-1nodesource1 of package nodejs](https://thepracticaldev.s3.amazonaws.com/i/eka4fqfxndw3pwjxvbd1.png)

I could have started with the InSpec [package](https://www.inspec.io/docs/reference/resources/package/) resource which would allow me to test a specific package and version of Node.js as well. This is extremely useful for example if you want to make sure a minimum version is installed (or a specific version is not installed for example due to a security issue!).

## Adding a Required NPM Package

As I continue to write my infrastructure code, I keep following the Red/Green/Refactor cycle, implementing small tests, then adding a feature, and then refactoring. There are [InSpec npm resources](https://www.inspec.io/docs/reference/resources/npm/) available beyond just the standard package resources. 

Interested in more Chef + Test Kitchen + InSpec + Azure content? Let me know in comments below and I'll add more. There is a lot more areas I could cover, but I'd like to focus on what is helpful.

## Cleaning Up My Azure Resources

Always remember to clean up cloud resources you use for development and testing. I clean up my instances with `kitchen destroy` and that deletes all the resources I created.

```
$ kitchen destroy
-----> Starting Kitchen (v2.0.1)
-----> Destroying <default-ubuntu-1804>...
       Azure environment: Azure
       Destroying Resource Group: kitchen-default-ubuntu-1804-20190424T071334
       Destroy operation accepted and will continue in the background.
       Finished destroying <default-ubuntu-1804> (0m1.61s).
-----> Kitchen is finished. (0m11.28s)
```       

## Additional Resources

* [Learn about Infrastructure as Code](https://docs.microsoft.com/en-us/azure/devops/learn/what-is-infrastructure-as-code?WT.mc_id=azureapril_devto-blog-cxa)
* [Test Driven Development with InSpec](https://learn.chef.io/modules/tdd-with-inspec#/)
* [Use InSpec for testing your Azure Infrastructure](https://docs.microsoft.com/en-us/azure/chef/chef-inspec-overview/?WT.mc_id=azureapril_devto-blog-cxa)

---
We'll be posting articles every day in April, so stay tuned or jump ahead and check out more tips and tricks [now](http://azuredev.tips).