pyATS aetest is a Python-based testing framework designed for writing and executing structured network test scripts. It allows you to create reusable test cases to verify that your network devices and configurations are functioning as expected.
In this section, we’ll introduce the basics of aetest, explore its structure, and walk through a simple example to get started.
pyATS AEtest Fundamental
What is the role of a testcase in network management, and why do we automate it?
A testcase is a block of code that checks a specific aspect of your network — for example, verifying whether an interface is up or a route is present. In the context of network management, testcases help validate that devices and configurations are working as expected.
We automate testcases to make them reusable, schedule them to run in the background, and generate clear and consistent reports.
The pyATS aetest framework is designed to standardize how testcases are defined and executed, making network testing more organized, repeatable, and scalable.
AEtest Structure
To write test cases using the aetest framework, you follow a predefined structure that includes one or more testcases.
The framework includes a “Common Setup” and a “Common Cleanup” section. These are shared across all test cases in a script and are typically used when you have multiple test cases. Common tasks like loading the testbed, connecting to devices, or other shared preparations are placed in the Common Setup, while shared cleanup tasks like disconnecting from devices go in the Common Cleanup.
Each individual test case also includes its own “Setup”, “Cleanup”, and one or more “Test” Sections in between. These sections are specific to that test case. For example, if your script contains only a single test case, you might skip the common setup and cleanup, and instead perform all necessary actions—such as connecting to a device or configuring the network—within the test case’s own setup and cleanup sections.
You can also modify the device configuration during the Setup phase to prepare the environment for testing, and then restore the original configuration in the Cleanup phase to ensure no changes persist after the test.
Section | Optional / Mandatory | What Happens in This Section |
---|---|---|
Common Setup | Optional | Prepares the test environment, such as loading testbed, connecting to devices, or setting up variables shared across testcases. |
Testcase - Setup | Optional | Prepares the specific environment or conditions required for that particular testcase. |
Testcase - TestX | Mandatory (at least one) | Contains the actual tests/validations (e.g., checking interfaces, routes, configs). You can have multiple test steps. |
Testcase - Cleanup | Optional | Cleans up after the testcase, like resetting configs or closing sessions if needed. |
Common Cleanup | Optional | Final cleanup after all testcases finish — disconnecting devices, logging results, or restoring original network state. |
This is the Python code structure used when writing test cases with aetest, including all key sections discussed earlier.
""" Automation Easy Testing (AEtest): a framework designed to standardize the definition and execution of network test cases. https://pubhub.devnetcloud.com/media/pyats/docs/aetest/index.html """ # Import necessary modules from pyats import aetest # AEtest framework is part of pyATS from genie.testbed import load # For loading testbed files # Common Setup section: Sets up the environment for all test cases class CommonSetup(aetest.CommonSetup): @aetest.subsection def connect_to_testbed(self): """ Connect to the devices in the testbed. This is where you load and connect to the devices using the testbed file. """ # Replace with actual testbed file path self.testbed = load('path_to_testbed.yaml') # Connect to all devices in the testbed self.testbed.connect() # Establish connections @aetest.subsection def prepare_testcases(self): """ Prepare for test cases. Configure test parameters, set up the environment, etc. """ pass # Placeholder for preparation steps # Testcase 1: Example of a test case with setup, two tests, and cleanup class TestcaseOne(aetest.Testcase): @aetest.setup def setup(self): """ Setup for TestcaseOne. Perform any necessary setup steps before the tests. """ pass # Placeholder for setup steps @aetest.test def test_one(self): """ First test in TestcaseOne. This is where the first test logic will be executed. Each test in this test case is executed sequentially. """ pass # Placeholder for first test logic @aetest.test def test_two(self): """ Second test in TestcaseOne. This is where the second test logic will be executed. """ pass # Placeholder for second test logic @aetest.cleanup def cleanup(self): """ Cleanup after TestcaseOne execution. Perform any necessary cleanup tasks after the tests. """ pass # Placeholder for cleanup steps # Testcase 2: Another test case example with setup, test, and cleanup class TestcaseTwo(aetest.Testcase): @aetest.setup def setup(self): """ Setup for TestcaseTwo. Prepare any resources required for the test. """ pass # Placeholder for setup steps @aetest.test def execute_test(self): """ Main test logic for TestcaseTwo. This is where the test is performed. """ pass # Placeholder for test logic @aetest.cleanup def cleanup(self): """ Cleanup after TestcaseTwo execution. Ensure resources are cleaned up after the test. """ pass # Placeholder for cleanup steps # Common Cleanup section: Disconnect from the testbed after all tests class CommonCleanup(aetest.CommonCleanup): @aetest.subsection def disconnect_from_testbed(self): """ Disconnect from the devices. This is where you disconnect all the devices in the testbed. """ self.testbed.disconnect() # Close connections # Main section to run the script if __name__ == '__main__': aetest.main() # Trigger AEtest main function to execute the test cases
pyATS AEtest Example
To better understand how the AEtest framework works, let’s walk through a simple example.
(majid) majid@majid-ubuntu:~/devnet/pyats$ cat 6.1.aetest_test_a_single_device.py from pyats import aetest from pyats.topology import loader # Load the testbed file testbed = loader.load('testbed.yaml') class CommonSetup(aetest.CommonSetup): @aetest.subsection def connect_to_devices(self): testbed.connect() class TestcaseOne(aetest.Testcase): @aetest.setup def setup(self): self.r1 = testbed.devices['R1'] self.l3_interfaces = self.r1.parse("show ip interface brief") @aetest.test def test1(self): print(self.l3_interfaces) @aetest.test def test2(self): for intf, details in self.l3_interfaces['interface'].items(): if details['status'] == 'up': print(f"Interface {intf} is up.") else: print(f"Interface {intf} is not up.") class CommonCleanup(aetest.CommonCleanup): @aetest.subsection def disconnect_from_devices(self): testbed.disconnect() if __name__ == '__main__': aetest.main()
In this script:
The testbed is loaded outside of any test class using the
loader.load()
function.A
CommonSetup
section is used to establish connections to all devices defined in the testbed.A
CommonCleanup
section ensures that all connections are properly disconnected at the end.There is one test case,
TestcaseOne
, which includes a setup section and two test sections:In the setup section, we access device
R1
and parse the output of the command „show ip interface brief“
.In test1, we simply print the parsed output of the command — this serves as a visual confirmation that the parser worked.
In test2, we perform a real verification: we iterate over all interfaces and check whether each one is up. A message is printed for each interface indicating whether it’s up or not.
This example highlights the typical AEtest structure, including setup, test, and cleanup phases, and demonstrates how to use parsed command output in real test logic.
When we run the script, we receive a well-structured report that highlights the advantages of using the AEtest framework.
The process begins with the common setup, which connects to all devices defined in the testbed.yaml
file. As shown in the output, the connection is successful and the result of this step is “PASSED”.
2025-04-19T11:43:14: %AETEST-INFO: The result of subsection connect_to_devices is => PASSED 2025-04-19T11:43:14: %AETEST-INFO: The result of common setup is => PASSED
Next, the setup section of TestcaseOne
is executed. During this step, the command “show
ip interface brief”
is run on device R1, and the output is parsed. This confirms that pyATS is able to retrieve and interpret device data correctly. The result of this section is also marked as “PASSED”.
2025-04-19T11:43:14: %AETEST-INFO: +------------------------------------------------------------------------------+ 2025-04-19T11:43:14: %AETEST-INFO: | Starting testcase TestcaseOne | 2025-04-19T11:43:14: %AETEST-INFO: +------------------------------------------------------------------------------+ 2025-04-19T11:43:14: %AETEST-INFO: +------------------------------------------------------------------------------+ 2025-04-19T11:43:14: %AETEST-INFO: | Starting section setup | 2025-04-19T11:43:14: %AETEST-INFO: +------------------------------------------------------------------------------+ 2025-04-19 11:43:14,575: %UNICON-INFO: +++ R1 with via 'cli': executing command 'show ip interface brief' +++ show ip interface brief Interface IP-Address OK? Method Status Protocol GigabitEthernet1 10.13.14.16 YES NVRAM up up GigabitEthernet2 10.13.15.16 YES NVRAM up up GigabitEthernet3 7.8.9.11 YES NVRAM administratively down down Loopback0 1.1.1.1 YES NVRAM up up Loopback10 10.10.10.10 YES NVRAM up up Loopback100 192.168.200.200 YES NVRAM up up R1# 2025-04-19T11:43:14: %AETEST-INFO: The result of section setup is => PASSED
Following that, the test1 section starts. Here, the parsed output of the “show ip interface brief”
command is printed in a structured dictionary format, showing interface details such as IP address, status, and protocol. This section also passes successfully.
2025-04-19T11:43:14: %AETEST-INFO: +------------------------------------------------------------------------------+ 2025-04-19T11:43:14: %AETEST-INFO: | Starting section test1 | 2025-04-19T11:43:14: %AETEST-INFO: +------------------------------------------------------------------------------+ {'interface': {'GigabitEthernet1': {'ip_address': '10.13.14.16', 'interface_is_ok': 'YES', 'method': 'NVRAM', 'status': 'up', 'protocol': 'up'}, 'GigabitEthernet2': {'ip_address': '10.13.15.16', 'interface_is_ok': 'YES', 'method': 'NVRAM', 'status': 'up', 'protocol': 'up'}, 'GigabitEthernet3': {'ip_address': '7.8.9.11', 'interface_is_ok': 'YES', 'method': 'NVRAM', 'status': 'administratively down', 'protocol': 'down'}, 'Loopback0': {'ip_address': '1.1.1.1', 'interface_is_ok': 'YES', 'method': 'NVRAM', 'status': 'up', 'protocol': 'up'}, 'Loopback10': {'ip_address': '10.10.10.10', 'interface_is_ok': 'YES', 'method': 'NVRAM', 'status': 'up', 'protocol': 'up'}, 'Loopback100': {'ip_address': '192.168.200.200', 'interface_is_ok': 'YES', 'method': 'NVRAM', 'status': 'up', 'protocol': 'up'}}} 2025-04-19T11:43:14: %AETEST-INFO: The result of section test1 is => PASSED
Then, the test2 section runs. It uses the parsed data to print the operational status of each interface—indicating whether it is “up” or “not up”. Again, this section completes with a “PASSED” result.
2025-04-19T11:43:14: %AETEST-INFO: +------------------------------------------------------------------------------+ 2025-04-19T11:43:14: %AETEST-INFO: | Starting section test2 | 2025-04-19T11:43:14: %AETEST-INFO: +------------------------------------------------------------------------------+ Interface GigabitEthernet1 is up. Interface GigabitEthernet2 is up. Interface GigabitEthernet3 is not up. Interface Loopback0 is up. Interface Loopback10 is up. Interface Loopback100 is up. 2025-04-19T11:43:14: %AETEST-INFO: The result of section test2 is => PASSED 2025-04-19T11:43:14: %AETEST-INFO: The result of testcase TestcaseOne is => PASSED
Finally, the common cleanup section is executed. It disconnects from all devices, and both the disconnect_from_devices
subsection and the overall cleanup are marked as “PASSED”.
2025-04-19T11:43:14: %AETEST-INFO: +------------------------------------------------------------------------------+ 2025-04-19T11:43:14: %AETEST-INFO: | Starting common cleanup | 2025-04-19T11:43:14: %AETEST-INFO: +------------------------------------------------------------------------------+ 2025-04-19T11:43:14: %AETEST-INFO: +------------------------------------------------------------------------------+ 2025-04-19T11:43:14: %AETEST-INFO: | Starting subsection disconnect_from_devices | 2025-04-19T11:43:14: %AETEST-INFO: +------------------------------------------------------------------------------+ 2025-04-19T11:43:25: %AETEST-INFO: The result of subsection disconnect_from_devices is => PASSED 2025-04-19T11:43:25: %AETEST-INFO: The result of common cleanup is => PASSED
At the end of the output, a detailed summary is provided. It shows the results of each section and subsection in a clear and organized format, including a 100% success rate, demonstrating the effectiveness and reliability of the AEtest framework.
2025-04-19T11:43:25: %AETEST-INFO: +------------------------------------------------------------------------------+ 2025-04-19T11:43:25: %AETEST-INFO: | Detailed Results | 2025-04-19T11:43:25: %AETEST-INFO: +------------------------------------------------------------------------------+ 2025-04-19T11:43:25: %AETEST-INFO: SECTIONS/TESTCASES RESULT 2025-04-19T11:43:25: %AETEST-INFO: -------------------------------------------------------------------------------- 2025-04-19T11:43:25: %AETEST-INFO: . 2025-04-19T11:43:25: %AETEST-INFO: |-- common_setup PASSED 2025-04-19T11:43:25: %AETEST-INFO: | `-- connect_to_devices PASSED 2025-04-19T11:43:25: %AETEST-INFO: |-- TestcaseOne PASSED 2025-04-19T11:43:25: %AETEST-INFO: | |-- setup PASSED 2025-04-19T11:43:25: %AETEST-INFO: | |-- test1 PASSED 2025-04-19T11:43:25: %AETEST-INFO: | `-- test2 PASSED 2025-04-19T11:43:25: %AETEST-INFO: `-- common_cleanup PASSED 2025-04-19T11:43:25: %AETEST-INFO: `-- disconnect_from_devices PASSED 2025-04-19T11:43:25: %AETEST-INFO: +------------------------------------------------------------------------------+ 2025-04-19T11:43:25: %AETEST-INFO: | Summary | 2025-04-19T11:43:25: %AETEST-INFO: +------------------------------------------------------------------------------+ 2025-04-19T11:43:25: %AETEST-INFO: Number of ABORTED 0 2025-04-19T11:43:25: %AETEST-INFO: Number of BLOCKED 0 2025-04-19T11:43:25: %AETEST-INFO: Number of ERRORED 0 2025-04-19T11:43:25: %AETEST-INFO: Number of FAILED 0 2025-04-19T11:43:25: %AETEST-INFO: Number of PASSED 3 2025-04-19T11:43:25: %AETEST-INFO: Number of PASSX 0 2025-04-19T11:43:25: %AETEST-INFO: Number of SKIPPED 0 2025-04-19T11:43:25: %AETEST-INFO: Total Number 3 2025-04-19T11:43:25: %AETEST-INFO: Success Rate 100.0% 2025-04-19T11:43:25: %AETEST-INFO: --------------------------------------------------------------------------------