Help us understand the problem. What is going on with this article?

pyATSの初歩

More than 3 years have passed since last update.

pyATSとは

pyATS は、Python Automated Test Systems の略で、python3 ベースのテストフレームワークです。Cisco によって開発されています。license は、Apache 2.0 です。

Document などの情報は、以下のリンクにあります。
Cisco DevNet: pyATS

pytest のように、pythonプログラムのテストに使用できますが、Device object や ConnectionManager object という router 等の network device のテストをするための機能も含まれています。
この記事では、とりあえず pyATS の基本機能を動作させてみただけで、Device object などは使っていません。
pyATS で Cisco IOS Router にアクセスした事例は、 「pyATSによるCisco IOS Routerのテスト例」 に記載しています。

インストール

環境

  • pyATS は、python 3.4 以上を必要とします。今回は、3.4.5を使いました。
  • python3 の development library が必要です。今回は、python34-devel.x86_64 を使いました。
  • CentOS7 上で動かしました。
  • pyATS は、4.0.0 を使用しています。 なお、pyATS 4.0.0 は、Linux と Mac OS には対応していますが、Windows 系は未サポートとなっています。

インストール方法

普通に pip でインストールできます。今回は、以下のように virtualenv で動かしています。

$ python3 -m virtualenv pyATS
$ cd pyATS
$ source bin/activate
$ pip install pyats

テストをしてみる

テスト対象

テスト対象として以下のようなクラスを使いました。

shape.py
#!/usr/bin/env python

class Shape(object):

    def __init__(self, name):
        self.name = name
        if name == 'triangle':
            self.sides = 3
        elif name == 'rectangle':
            self.sides = 4
        elif name == 'pentagon':
            self.sides = 6
        else:
            self.sides = 0

テストスクリプトの構造

テストスクリプトは、ats.aetest モジュールの Class を使って記述します。
pyATS では、スクリプトは以下のような構造になっています。
* 0または1個の CommonSetup Class
* 1個以上の Testcase Class
* 0または1個の CommonCleanup Class

CommonSetup と CommonCleanup は、複数の subsection を method として持ちます。

Testcase は更に以下の sub section に分かれます。
* 0または1個の setup method
* 1個以上の test method
* 0または1個の cleanup method

それぞれ、@setup, @test, @cleanup decoratorを使って修飾することで、その subsection と aetest に認識されます。

pyATS を実行すると最初に CommonSetup が実行され、その次に Testcase が記述された順番で実行されます。最後に、CommonCleanup が実行されます。
ats.aetest は、各セクション毎に、実行結果をレポートする機能ももっています。

テストスクリプトの例

Shape class をテストするテストケースを書いてみます。
Testcase classのみを使います。
name が triangle, rectangle, pentagon の Shape object を作って、sides の値が正しいかをcheckします。
pentagon の時には、間違った sides が設定されるので、そのケースは fail になるはずです。

simple_test.py
from ats import aetest
from shape import Shape

# test section within Testcases
class Testcase(aetest.Testcase):

    # define test section by applying @test decorator
    @aetest.test
    def testcase_one(self):
        shape = Shape('triangle')
        assert(shape.sides == 3)

    @aetest.test
    def testcase_two(self):
        shape = Shape('rectangle')
        assert(shape.sides == 4)

    @aetest.test
    def testcase_three(self):
        shape = Shape('pentagon')
        assert(shape.sides == 5)

実行方法

前記のテストスクリプトの最後で、ats.aetest.main() を実行すれば、テストを実行できます。今回は、以下のような wrapper を作成して、任意のスクリプトを実行できるようにしました。

run_test.py
#!/usr/bin/env python
from ats.aetest import main
import sys

testscript = sys.argv[1]
main(testable = testscript)

以下のようにして、simple_test.py を実行します。

$ ./run_test.py simple_test.py

実行結果

結果は、以下のようになります。
testcase_three で fail が発生しています。

2017-12-06T23:53:14: %AETEST-INFO: Starting testcase Testcase
./run_test.py:6: DeprecationWarning: Starting v3.0.0, section.id is deprecated and replaced by section.uid. Please modify your scripts. This will be removed next release
  main(testable = testscript)
2017-12-06T23:53:14: %AETEST-INFO: Starting section testcase_one
2017-12-06T23:53:14: %AETEST-INFO: The result of section testcase_one is => PASSED
2017-12-06T23:53:14: %AETEST-INFO: Starting section testcase_two
2017-12-06T23:53:14: %AETEST-INFO: The result of section testcase_two is => PASSED
2017-12-06T23:53:14: %AETEST-INFO: Starting section testcase_three
2017-12-06T23:53:14: %AETEST-WARNING: An assertion failure was caught:
2017-12-06T23:53:14: %AETEST-WARNING: Traceback (most recent call last):
2017-12-06T23:53:14: %AETEST-WARNING:   File "/home/tokatsu/pyATS/myCases/simple_case/simple_test.py", line 21, in testcase_three
2017-12-06T23:53:14: %AETEST-WARNING:     assert(shape.sides == 5)
2017-12-06T23:53:14: %AETEST-WARNING: AssertionError
2017-12-06T23:53:14: %AETEST-INFO: The result of section testcase_three is => FAILED
2017-12-06T23:53:14: %AETEST-INFO: The result of testcase Testcase is => FAILED
2017-12-06T23:53:14: %AETEST-INFO: +------------------------------------------------------------------------------+
2017-12-06T23:53:14: %AETEST-INFO: |                               Detailed Results                               |
2017-12-06T23:53:14: %AETEST-INFO: +------------------------------------------------------------------------------+
2017-12-06T23:53:14: %AETEST-INFO:  SECTIONS/TESTCASES                                                      RESULT
2017-12-06T23:53:14: %AETEST-INFO: --------------------------------------------------------------------------------
2017-12-06T23:53:14: %AETEST-INFO: .
2017-12-06T23:53:14: %AETEST-INFO: `-- Testcase                                                             FAILED
2017-12-06T23:53:14: %AETEST-INFO:     |-- testcase_one                                                     PASSED
2017-12-06T23:53:14: %AETEST-INFO:     |-- testcase_two                                                     PASSED
2017-12-06T23:53:14: %AETEST-INFO:     `-- testcase_three                                                   FAILED
2017-12-06T23:53:14: %AETEST-INFO: +------------------------------------------------------------------------------+
2017-12-06T23:53:14: %AETEST-INFO: |                                   Summary                                    |
2017-12-06T23:53:14: %AETEST-INFO: +------------------------------------------------------------------------------+
2017-12-06T23:53:14: %AETEST-INFO:  Number of ABORTED                                                            0
2017-12-06T23:53:14: %AETEST-INFO:  Number of BLOCKED                                                            0
2017-12-06T23:53:14: %AETEST-INFO:  Number of ERRORED                                                            0
2017-12-06T23:53:14: %AETEST-INFO:  Number of FAILED                                                             1
2017-12-06T23:53:14: %AETEST-INFO:  Number of PASSED                                                             0
2017-12-06T23:53:14: %AETEST-INFO:  Number of PASSX                                                              0
2017-12-06T23:53:14: %AETEST-INFO:  Number of SKIPPED                                                            0
2017-12-06T23:53:14: %AETEST-INFO: --------------------------------------------------------------------------------

Loopを使ってみる

同じようなテストケースを3回書くのは冗長なので、pyATS の loop 機能を使って前記のスクリプトを書き直してみました。

Loop を使った Testcase

Loop を実行するには、@loop decorator を使います。@loop の中で指定した loop parameter を順に使って、loop を実行します。

simple_test_loop.py
from ats import aetest
from shape import Shape

# test section within Testcases
class Testcase(aetest.Testcase):

    # define test section by applying @test decorator
    @aetest.loop(name = ['triangle', 'rectangle', 'pentagon'], sides = [3, 4, 5])
    @aetest.test
    def testcase_one(self, name, sides):
        shape = Shape(name)
        assert(shape.sides == sides)

実行結果

test methond の名前以外は、simple_test.py と同じ結果になります。
method の名前は、元の名前に loop parameter の値を連結したものになります。

2017-12-07T00:00:33: %AETEST-INFO: Starting testcase Testcase
./run_test.py:6: DeprecationWarning: Starting v3.0.0, section.id is deprecated and replaced by section.uid. Please modify your scripts. This will be removed next release
  main(testable = testscript)
2017-12-07T00:00:33: %AETEST-INFO: Starting section testcase_one[name=triangle,sides=3]
2017-12-07T00:00:33: %AETEST-INFO: The result of section testcase_one[name=triangle,sides=3] is => PASSED
2017-12-07T00:00:33: %AETEST-INFO: Starting section testcase_one[name=rectangle,sides=4]
2017-12-07T00:00:33: %AETEST-INFO: The result of section testcase_one[name=rectangle,sides=4] is => PASSED
2017-12-07T00:00:33: %AETEST-INFO: Starting section testcase_one[name=pentagon,sides=5]
2017-12-07T00:00:33: %AETEST-WARNING: An assertion failure was caught:
2017-12-07T00:00:33: %AETEST-WARNING: Traceback (most recent call last):
2017-12-07T00:00:33: %AETEST-WARNING:   File "/home/tokatsu/pyATS/myCases/simple_case/simple_test_loop.py", line 12, in testcase_one
2017-12-07T00:00:33: %AETEST-WARNING:     assert(shape.sides == sides)
2017-12-07T00:00:33: %AETEST-WARNING: AssertionError
2017-12-07T00:00:33: %AETEST-INFO: The result of section testcase_one[name=pentagon,sides=5] is => FAILED
2017-12-07T00:00:33: %AETEST-INFO: The result of testcase Testcase is => FAILED
2017-12-07T00:00:33: %AETEST-INFO: +------------------------------------------------------------------------------+
2017-12-07T00:00:33: %AETEST-INFO: |                               Detailed Results                               |
2017-12-07T00:00:33: %AETEST-INFO: +------------------------------------------------------------------------------+
2017-12-07T00:00:33: %AETEST-INFO:  SECTIONS/TESTCASES                                                      RESULT
2017-12-07T00:00:33: %AETEST-INFO: --------------------------------------------------------------------------------
2017-12-07T00:00:33: %AETEST-INFO: .
2017-12-07T00:00:33: %AETEST-INFO: `-- Testcase                                                             FAILED
2017-12-07T00:00:33: %AETEST-INFO:     |-- testcase_one[name=triangle,sides=3]                              PASSED
2017-12-07T00:00:33: %AETEST-INFO:     |-- testcase_one[name=rectangle,sides=4]                             PASSED
2017-12-07T00:00:33: %AETEST-INFO:     `-- testcase_one[name=pentagon,sides=5]                              FAILED
2017-12-07T00:00:33: %AETEST-INFO: +------------------------------------------------------------------------------+
2017-12-07T00:00:33: %AETEST-INFO: |                                   Summary                                    |
2017-12-07T00:00:33: %AETEST-INFO: +------------------------------------------------------------------------------+
2017-12-07T00:00:33: %AETEST-INFO:  Number of ABORTED                                                            0
2017-12-07T00:00:33: %AETEST-INFO:  Number of BLOCKED                                                            0
2017-12-07T00:00:33: %AETEST-INFO:  Number of ERRORED                                                            0
2017-12-07T00:00:33: %AETEST-INFO:  Number of FAILED                                                             1
2017-12-07T00:00:33: %AETEST-INFO:  Number of PASSED                                                             0
2017-12-07T00:00:33: %AETEST-INFO:  Number of PASSX                                                              0
2017-12-07T00:00:33: %AETEST-INFO:  Number of SKIPPED                                                            0
2017-12-07T00:00:33: %AETEST-INFO: --------------------------------------------------------------------------------
tokatsu
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away