Halloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanHalloween DealsAmazon USOctober picks are moving - compare before checkoutAmazon US: current deals, useful picks and tech finds.See Picks×
VGSOURCES
Get listed

AnsiblePATCH 2026.10.15

How to Test Your Ansible Deployments with InSpec and Test Kitchen

By VGSources Team 10 min read

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The reliable pattern is simple: let Test Kitchen create an isolated machine, let Ansible converge the deployment, and let Chef InSpec verify the machine’s observable state through the kitchen-inspec verifier. Run the stages independently while developing, then use Kitchen’s full create → converge → setup → verify → destroy lifecycle in CI.

This approach turns an Ansible role’s assumptions into executable checks for packages, services, ports, files, users, permissions, configuration values, and application responses—without treating a successful playbook run as proof that the deployment works.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What each tool contributes

Ansible applies the change

Ansible remains the system under test. Your playbook or role installs packages, writes configuration, creates service accounts, enables services, opens the intended listeners, and performs any application setup. Its output tells you what tasks changed, skipped, or failed, but it does not independently prove that the resulting machine satisfies the deployment contract.

Test Kitchen supplies repeatable targets

Test Kitchen is a harness for executing infrastructure code on one or more platforms in isolation. A Kitchen instance is the combination of a suite and a platform, such as the default-ubuntu instance produced by a suite named default and a platform named ubuntu. Drivers create the target, provisioners run infrastructure code, and suites define what is being tested.

kitchen-inspec connects verification to Kitchen

The kitchen-inspec verifier runs Chef InSpec controls against the instance that Kitchen created. Set verifier: name: inspec in kitchen.yml. The verifier can use Kitchen’s host and port information by default, or you can provide explicit connection settings when the target requires them.

InSpec checks the resulting machine

Chef InSpec expresses compliance, security, and policy expectations in a human- and machine-readable language. It can inspect a local machine or connect to a remote host over SSH. Its resource model lets a control describe what must be true without coupling every assertion to the exact Ansible task that produced it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Start with a deployment contract

Before writing Kitchen configuration, list the outcomes that operators and users depend on. These are the assertions that should survive a refactor of the role.

  • The required package is installed, and its version is within the supported range.
  • The service is enabled and running after convergence.
  • Only intended ports are listening, with TLS enabled where the deployment requires it.
  • Configuration files contain required values and have the correct owner and permissions.
  • The service account exists with the expected shell, groups, home directory, and ownership.
  • An application endpoint returns the expected status or response header.
  • A second convergence is idempotent, meaning it does not make unnecessary changes.

The first six items are final-state checks. Idempotence is a behavior check and should be tested separately rather than inferred from a clean InSpec run.

Build the Kitchen project

Choose a driver and target platforms

The driver determines how an isolated target is created. A container driver can be fast for package and service checks; a virtual-machine or cloud driver can provide stronger operating-system fidelity. Select platforms that represent the systems your role actually supports, and add more than one platform when package names, service managers, paths, or defaults differ.

Define the provisioner, verifier, and suite

A minimal project has a Kitchen configuration, an Ansible convergence playbook, and an InSpec test directory. The following shape uses a Docker driver, an Ubuntu platform, the Ansible provisioner, and kitchen-inspec:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
provisioner:
  name: ansible

driver:
  name: docker

platforms:
  - name: ubuntu

verifier:
  name: inspec

suites:
  - name: default
    provisioner:
      playbook: converge.yml
    verifier:
      inspec_tests:
        - test/integration/default

The exact driver and Ansible provisioner options depend on the Kitchen plugins and target environment. Pin compatible plugin versions in the project and validate those versions in continuous integration; a configuration that works only because of locally installed, floating dependencies is not repeatable.

Use explicit variables and inventory

Keep variables, inventory, and environment-specific assumptions visible in the suite configuration or files checked into the project. Explicit inputs make it easier to tell whether a failure came from the playbook, the target image, or the verifier. Avoid silently depending on a developer’s workstation credentials or globally installed Ansible configuration.

Organize InSpec controls where Kitchen can find them

kitchen-inspec’s default convention is test/integration/%suite%. For the default suite, that resolves to test/integration/default. You can override the location with inspec_tests.

A suite can point to several kinds of profile source:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Source When it fits Trade-off
Local directory Controls are specific to the role and reviewed with its code. Assertions are easy to change with the deployment but are less reusable.
Git repository Several repositories need a shared profile with normal version review. CI must fetch the requested revision and remain available to the build.
Supermarket profile A centrally published profile is appropriate for the organization. Execution depends on profile availability and version selection.
Compliance profile A team already maintains controls as a compliance profile. Profile ownership and update cadence need to be coordinated with the deployment.

Local controls are usually the clearest starting point. Move stable, cross-project policy checks into a shared profile only when the reuse and independent versioning justify the additional dependency.

Write controls around observable behavior

Packages

Check that the package exists, and check a version only when the deployed version is part of the contract. A version assertion that merely mirrors an implementation detail can create unnecessary maintenance.

describe package('nginx') do
  it { should be_installed }
end

If a particular release is required, express that requirement explicitly using the version matcher supported by your InSpec version, and document whether the requirement is an exact version or an acceptable range.

Services

describe service('nginx') do
  it { should be_enabled }
  it { should be_running }
end

This catches a common gap: a playbook can start a service during convergence without enabling it for the next reboot, or it can enable a unit that is currently unhealthy.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Ports and transport

describe port(443) do
  it { should be_listening }
end

For a deployment that requires encrypted transport, combine a listener check with an application-level request that validates the expected HTTPS behavior. Also consider a negative check for an unintended clear-text listener when that is part of the security contract. Do not assert a port merely because the example role happens to use it; assert only ports that the supported deployment promises.

Files and permissions

describe file('/etc/nginx/nginx.conf') do
  it { should exist }
  its('mode') { should cmp '0644' }
  its('owner') { should eq 'root' }
  its('group') { should eq 'root' }
  its('content') { should match /worker_processes/ }
end

Use content checks for values that matter, such as a required upstream, bind address, or security setting. Keep the assertion focused enough that a harmless formatting change does not fail the deployment.

Users and service accounts

describe user('app') do
  it { should exist }
  its('shell') { should eq '/usr/sbin/nologin' }
  its('groups') { should include 'app' }
end

Check ownership on application directories separately. A service account can exist with the right shell while files remain writable by an unintended group.

Application responses

describe http('http://127.0.0.1/health') do
  its('status') { should cmp 200 }
end

An endpoint check verifies that the service is not merely running but can answer a request. Use a local address when the test is intended to isolate the machine, and add externally meaningful checks in a separate integration layer when DNS, load balancers, certificates, or dependencies are outside the Kitchen instance.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Run the lifecycle deliberately

During development, separate stages make diagnosis faster. In CI, the complete lifecycle gives every run a clean target and predictable cleanup.

  1. Create: Run kitchen create default-ubuntu to create the isolated instance. Use kitchen list first if you need the exact generated instance name.
  2. Converge: Run kitchen converge default-ubuntu to execute the Ansible playbook. Treat an Ansible task failure as a provisioning failure, not an InSpec failure.
  3. Setup: Kitchen performs the setup stage needed by the verifier and transport. If setup fails, inspect connectivity, authentication, the target image, and verifier connection settings before changing controls.
  4. Verify: Run kitchen verify default-ubuntu. kitchen-inspec connects to the Kitchen host and evaluates the controls in the configured profile.
  5. Destroy: Run kitchen destroy default-ubuntu when you are finished, especially after debugging a failure.
  6. Test end to end: Run kitchen test default-ubuntu to execute the documented create → converge → setup → verify → destroy flow.

Use the instance-specific form while iterating, then run the full suite and platform matrix before merging. If you need to inspect a failed machine, preserve it temporarily for diagnosis and destroy it once the investigation is complete.

Separate provisioning failures from verification failures

Symptom Likely layer First checks
Kitchen cannot create the instance Driver or platform Driver installation, image availability, container or VM permissions, and platform name.
Ansible cannot connect Provisioner transport Inventory, SSH or connection settings, credentials, Python availability, and target readiness.
Ansible task fails Playbook or target assumptions Task output, variables, package repositories, service names, paths, and operating-system differences.
Setup cannot reach the host Kitchen transport or verifier setup Kitchen’s host and port, explicit verifier connection options, firewall rules, and authentication.
InSpec reports a missing package or service Deployment contract or control Whether convergence completed, the target’s actual package and unit names, and the control’s platform assumptions.
An HTTP control returns the wrong status Application configuration or readiness Service logs, bind address, listening port, TLS requirements, and whether the endpoint needs startup time or dependencies.

Do not “fix” a failing control by weakening it until you have confirmed that the requirement itself is wrong. A failed assertion often exposes an undocumented platform difference or an incomplete deployment.

Test idempotence as a separate property

Final-state controls can all pass even when a role changes files or restarts services on every run. To check idempotence, converge the same instance again and inspect Ansible’s second-run output for unexpected changes. Pay particular attention to templated files, generated secrets, archive extraction, service handlers, and commands that lack a meaningful change condition.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Keep this check distinct from InSpec’s state assertions. InSpec answers whether the machine is in the required state; the repeated-convergence check answers whether the role reaches that state without continuing to mutate it.

Design a useful platform matrix

Platform coverage should reflect supported deployments rather than every image that a driver can launch. For each additional platform, decide whether it adds meaningful confidence.

Dimension Question to answer
Isolation Does the driver prevent host state from masking failures?
Operating-system fidelity Does the image use the same package manager, service manager, paths, and defaults as production?
Provisioning time Can the target start quickly enough for the frequency of CI runs?
Transport and authentication Does the test exercise the SSH or connection behavior used in deployment?
CI availability Can the build environment create the target reliably with the required permissions?
Parallelism Can multiple platform and suite combinations run without exhausting CI capacity?
Cleanup cost Will failed jobs leave resources that require manual intervention?
Production parity Are the image, kernel expectations, and base packages close enough to reveal real defects?

Use separate suites when the deployment contract genuinely differs. Use one suite with multiple platforms when the same observable requirements should hold everywhere.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Make CI results useful

Run the matrix on every change that affects the role, its defaults, its dependencies, or its InSpec controls. Retain the Kitchen and Ansible logs so a failed verification can be traced back to the convergence that produced the machine.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When auditability matters, retain machine-readable InSpec output as a CI artifact. The InSpec command set supports formats including JSON; for a profile run outside Kitchen, the form is:

inspec exec test/integration/default --reporter json

Use the verifier’s supported reporting configuration when the run is launched through Kitchen, and confirm the resulting file is uploaded by the CI job. Keep human-readable output as well; JSON is useful for systems and retention, while console output is faster for a developer diagnosing a failed control.

Improve the controls without overfitting them

  • Assert the package or service that users depend on, not an unrelated implementation artifact.
  • Check security-sensitive permissions and ownership explicitly.
  • Prefer a meaningful configuration value or endpoint response over matching an entire generated file.
  • Use platform conditionals only when the contract truly differs; excessive conditionals can hide an unsupported platform.
  • Give controls names that describe the requirement, so a CI failure explains what broke.
  • Keep external dependency checks separate from host checks when the dependency is not created by Kitchen.
  • Version shared profiles and review profile changes with the same care as playbook changes.

A practical project layout

A small repository can remain easy to navigate with a layout like this:

.
├── .kitchen.yml
├── converge.yml
├── roles/
│   └── application/
└── test/
    └── integration/
        └── default/
            ├── controls/
            │   └── deployment.rb
            └── inspec.yml

The exact role layout is up to your Ansible project. The important boundary is that converge.yml expresses how the target is built and the InSpec controls express what must be true afterward.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Common design mistakes

Testing only whether Ansible finished

A playbook can complete while a service is disabled, a configuration file is world-writable, or an endpoint is unreachable. Add state and behavior controls for the outcomes that matter.

Using a target unlike production

A fast container may not expose systemd behavior, kernel features, storage layout, or network boundaries that production relies on. Keep the fast target for broad feedback, and add a more faithful driver or image for assumptions the container cannot exercise.

Putting every assertion in one control file

Group controls by contract area—packages, service, configuration, access, and endpoint behavior—so failures are scannable and profile reuse remains possible.

Leaving instances behind

Unmanaged instances create stale state and consume CI resources. Use kitchen destroy after debugging and the complete kitchen test lifecycle in automated runs.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Definition of done

  • A clean Kitchen instance can be created with pinned, compatible plugins and a declared platform.
  • Ansible converges with explicit inventory and variables.
  • InSpec verifies packages, services, listeners, files, users, permissions, and application behavior required by the contract.
  • A second convergence is checked for unnecessary changes.
  • Supported platforms are exercised according to production differences and CI capacity.
  • Failures identify whether creation, transport, convergence, setup, or verification broke.
  • Instances are destroyed and machine-readable results are retained when auditability requires them.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

AnsibleChef InSpecConfiguration managementDevOpsinfrastructure testingkitchen-inspecTest Kitchen

Leave a reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.