[Day #88 PyATS Series] Write Unit Tests for Your pyATS Libraries (Pytest) Using pyATS for Cisco [Python for Network Engineer]
Table of Contents
Introduction on the Key Points
Welcome to Day #87 of our 101 Days of pyATS (Vendor-Agnostic) series, where we focus on elevating your network automation workflows into production-grade frameworks. In this Article, we will deep-dive into writing unit tests for pyATS libraries using Pytest, an essential skill for every Python for Network Engineer aiming to build robust, maintainable automation solutions.
Unit testing ensures that every function in your pyATS library behaves exactly as expected, delivering confidence in your automation workflows. We will focus on realistic, production-ready examples, emphasizing both CLI and GUI validation.
You’ll learn to:
- Structure pyATS libraries for testability.
- Use Pytest for efficient unit test automation.
- Validate mock network interactions.
- Create repeatable, scalable test cases.
- Build a strong test-driven automation pipeline.
By the end of this Article, you’ll have a complete, validated workflow for developing reliable automation libraries, ready to integrate into CI/CD pipelines and production environments.
Topology Overview
Although unit tests focus on isolated code behavior, it helps to visualize a simplified network topology to understand the data flow context.

- The unit tests simulate interactions with multi-vendor devices.
- Real CLI commands and responses are replaced by mocks for reproducibility.
- The goal: Ensure that our custom library methods return correct parsed data, handle exceptions gracefully, and interact with devices as expected.
Topology & Communications
We focus purely on simulated interactions:
- No physical device connection is made during unit tests.
- Device methods are mocked using Python’s
unittest.mock
framework. - Example interactions:
- Sending
show version
CLI commands. - Parsing responses for device serial numbers, uptime, or interfaces.
- Raising simulated exceptions for negative test cases.
- Sending
Workflow Script (Library and Unit Test Example)
a) Sample pyATS Library (network_utils.py
)
from genie.libs.conf.base import Device class NetworkUtils: def __init__(self, device: Device): self.device = device def get_serial_number(self): try: output = self.device.execute('show version | include System serial number') serial = output.split(":")[1].strip() return serial except Exception as e: raise RuntimeError(f"Failed to retrieve serial number: {str(e)}") def get_interface_status(self): try: output = self.device.execute('show interfaces status') interfaces = [] for line in output.splitlines(): if 'connected' in line: interfaces.append(line.split()[0]) return interfaces except Exception as e: raise RuntimeError(f"Failed to retrieve interface status: {str(e)}")
b) Unit Test Script (test_network_utils.py
)
import pytest from unittest.mock import MagicMock from network_utils import NetworkUtils @pytest.fixture def mock_device(): mock = MagicMock() return mock def test_get_serial_number_success(mock_device): mock_device.execute.return_value = "System serial number: CISCO12345" utils = NetworkUtils(mock_device) serial = utils.get_serial_number() assert serial == "CISCO12345" mock_device.execute.assert_called_with('show version | include System serial number') def test_get_serial_number_failure(mock_device): mock_device.execute.side_effect = Exception("Connection Error") utils = NetworkUtils(mock_device) with pytest.raises(RuntimeError) as excinfo: utils.get_serial_number() assert "Failed to retrieve serial number" in str(excinfo.value) def test_get_interface_status_success(mock_device): mock_device.execute.return_value = "Gi1/0/1 connected\nGi1/0/2 notconnect\nGi1/0/3 connected" utils = NetworkUtils(mock_device) interfaces = utils.get_interface_status() assert interfaces == ['Gi1/0/1', 'Gi1/0/3'] mock_device.execute.assert_called_with('show interfaces status') def test_get_interface_status_failure(mock_device): mock_device.execute.side_effect = Exception("CLI Error") utils = NetworkUtils(mock_device) with pytest.raises(RuntimeError) as excinfo: utils.get_interface_status() assert "Failed to retrieve interface status" in str(excinfo.value)
Explanation by Line
a) Library Code Breakdown
- get_serial_number():
- Executes
show version
command. - Parses serial number from output.
- Raises
RuntimeError
if something goes wrong.
- Executes
- get_interface_status():
- Executes
show interfaces status
. - Parses and returns a list of connected interfaces.
- Executes
b) Unit Test Breakdown
- Fixtures:
mock_device()
provides a reusable mock object.
- test_get_serial_number_success():
- Mocks successful CLI output.
- Asserts correct serial is returned.
- test_get_serial_number_failure():
- Mocks CLI failure.
- Asserts exception is raised.
- test_get_interface_status_success():
- Mocks a typical interfaces output.
- Asserts correct interfaces are returned.
- test_get_interface_status_failure():
- Mocks CLI failure.
- Asserts proper exception handling.
testbed.yml Example
testbed: name: unit_test_testbed credentials: default: username: admin password: Cisco123 devices: cisco_test_device: os: iosxe type: router connections: cli: protocol: ssh ip: 10.1.1.100
Although unit tests run in isolation, having a testbed helps define expected devices and structure.
Post-validation CLI (Simulated Expected Output)
$ pytest test_network_utils.py =========================== test session starts ============================ platform linux -- Python 3.8.10, pytest-7.1.2 collected 4 items test_network_utils.py .... [100%] ============================ 4 passed in 0.85s =============================
Example Output of get_serial_number()
:
System serial number: CISCO12345
Example Output of get_interface_status()
:
Gi1/0/1 Gi1/0/3
FAQs
Q1. Why should network engineers write unit tests for pyATS libraries?
A1. Unit tests ensure that individual functions or modules in your pyATS libraries behave as expected. They help catch errors early, improve code reliability, and provide confidence when making changes or refactoring automation scripts.
Q2. How does Pytest integrate with pyATS?
A2. Pytest is a Python testing framework that can run pyATS library functions as unit tests. By importing pyATS modules into Pytest test cases, you can validate outputs, handle exceptions, and ensure your automation logic works as intended.
Q3. What types of functions should be unit-tested in pyATS libraries?
A3. Functions that interact with device data, parse CLI output, perform validation checks, or handle configuration changes should be unit-tested. This includes both utility functions and workflow-level functions that are reused across scripts.
Q4. How do you mock network devices in unit tests?
A4. You can use mocking libraries like unittest.mock
to simulate device responses. This allows you to test parsing, validation, and business logic without needing live devices, making testing faster and safer.
Q5. Can unit tests verify multi-vendor compatibility?
A5. Yes. By creating mocked responses for different vendor OS outputs (Cisco IOS, Arista EOS, Juniper Junos), you can ensure that your pyATS library handles all supported platforms consistently.
Q6. How are test results reported?
A6. Pytest provides detailed reports showing passed, failed, or skipped tests. Combined with structured logging, it can highlight which function or module failed and why, facilitating quick debugging.
Q7. How do unit tests fit into CI/CD pipelines for network automation?
A7. Unit tests can be run automatically whenever changes are made to pyATS libraries. This ensures that updates do not break existing workflows and supports production-ready, reliable network automation deployments.
YouTube Link
Watch the Complete Python for Network Engineer: Write Unit Tests for Your pyATS Libraries (Pytest) Using pyATS for Cisco [Python for Network Engineer] Lab Demo & Explanation on our channel:
Join Our Training
You now have a full production-ready framework to write robust unit tests for your pyATS automation libraries using Pytest. This approach empowers you to build reliable, scalable, and maintainable automation solutions.
Elevate your career as a Python for Network Engineer by mastering automated testing, network programmability, and advanced Python scripting.
Join Trainer Sagar Dhawan’s 3-Month Instructor-Led Training Program for hands-on guidance, real-world use cases, and career-focused skills development.
Enroll now:
https://course.networkjourney.com/python-ansible-api-cisco-devnet-for-network-engineers/
Enroll Now & Future‑Proof Your Career
Email: info@networkjourney.com
WhatsApp / Call: +91 97395 21088