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.

pyATS AEtest Definition
pyATS AEtest Definition

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.

AEtest Structure
AEtest Structure

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: --------------------------------------------------------------------------------
Back to: Network Automation with pyATS & Genie (in Progress) > Automating Network Testcases with AEtest

Leave a Reply

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


Post comment