セキュリティスキャナーの自動テスト用のマルチコンポーネントシステムを開発する過程で、個々のテスト機能のコードの整合性を監視し、修正を実施するという問題に直面しました。
システムが起動する書面による機能テストの数はすでに数千を超えており、増え続けています。 この場合、1つの機能テストは1つの機能です。 この開発方法では、Readyのステータスをテストに割り当てた後、長い間そのことを忘れられます。
一方、他のテスト機能の開発プロセスでは、多くの場合、リファクタリングが必要になります。 さらに、このプロセスは、テスター自動化エンジニアの不注意により、既に終了したデバッグ済みテストに影響を与える可能性があります。
多くのモジュールや機能に影響する場合でも、プログラム自体をリファクタリングすることは一般的で非常に便利なことです。 ただし、テスト機能に関しては、常にそうとは限りません。 各テストは、特定の検証アルゴリズムを実装するように設計されています。 作成者が作成した検証ロジックは、テストコードにわずかな変更を加えた場合でも違反する場合があります。
このような状況の悪影響を回避するために、テスト関数のコードを修正するメカニズムを開発しました。これにより、関数の整合性を同時に制御し、コードを複製できます。
メカニズム
各関数について、リビジョン、ハッシュのセット、および関数コードを定義できます。
(func_hash, func_source)
すべての重要な機能を改訂辞書に追加できます。
{"funcName1": (funcName1_hash, funcName1_source), "funcName2": (funcName2_hash, funcName2_source), ...}
たとえば、私たちにとって、すでに開発されたテストを備えたすべての機能は重要です。 すべてのリビジョンは、特別なテキストファイル(リビジョンファイル)に保存できます。このファイルには、最後のリビジョンの日付とリビジョンディクショナリのリストが保存されます。
[revision's last date-n-time, {revisions}]
テストシステムの次のリリースの前に、改訂担当のスペシャリストは、機能コードの変更を追跡し、必要に応じて、古いテストのコードを短時間で復元し、単に改訂からコピーすることができます。
もちろん、コード検査やリポジトリ内のツール(GIT、SVNなど)の使用など、問題に対する代替ソリューションがあります。 ただし、数百のテストを自動的に変更する場合、検査は役に立たず、数回のマージ後にリポジトリツールを使用してコードの変更を追跡するのは面倒で長いプロセスです。 さらに、通常、ユニットテストはテスト関数に記述されていませんが、関数の品質と不変性を制御する必要性は残っています。このメカニズムは修正メカニズムによっても解決できます。
コード
上記のアイデアを実装するために、小さなモジュールFileRevision.pyがPythonで作成されました。 その中で使用可能なRevision()クラスをプロジェクトにインポートして、必要な機能のリビジョンを追加できます。
モジュールをわずかに変更したら、たとえばリビジョンファイルの圧縮を追加で実装できますが、小規模なプロジェクトではそれほど重要ではありません。
コードは
リンクから入手できます。
モジュールの実装
クラスリビジョン():__init __()#パラメーターの初期化 def __init__(self, fileRevision='revision.txt'): self.fileRevision = fileRevision self.mainRevision = self._ReadFromFile(self.fileRevision)
_ReadFromFile()#ファイルからリビジョンを取得する def _ReadFromFile(self, file=None): """ Helper function that parse and return revision from file. """ revision = [None, {}] if file == None: file = self.fileRevision try: if os.path.exists(file) and os.path.isfile(file): with open(file) as fH: revision = eval(fH.read()) except: traceback.print_exc() finally: return revision
_WriteToFile()#ファイルにリビジョンを書き込みます。 def _WriteToFile(self, revision=[None, {}], file=None): """ Helper procedure than trying to write given revision to file. """ status = False if file == None: file = self.fileRevision try: with open(file, "w") as fH: fH.write(str(revision)) status = True except: traceback.print_exc() finally: return status
_GetOld()#関数の前のリビジョンを取得します。 def _GetOld(self, func=None): """ Get old revision for given function and return tuple: (old_hash, old_source). """ funcHashOld = None
_GetNew()#関数の新しいリビジョンを取得します。 def _GetNew(self, func=None): """ Get new revision for given function and return tuple: (new_hash, new_source). """ funcSourceNew = None
_Similar()#2つのリビジョンの比較。 def _Similar(self, hashOld, sourceOld, hashNew, sourceNew): """ Checks if given params for modified then return tuple with revision's diff: (old_revision, new_revision), otherwise return None. """ similar = True
Update()#指定された関数のリビジョンを更新します。 def Update(self, func=None): """ Set new revision for function. revision = [revision date-n-time, {"funcName1": (funcName1_hash, funcName1_source), {"funcName2": (funcName2_hash, funcName2_source), ...}] """ status = False if func: try: funcSourceNew = inspect.getsource(func)
DeleteAll()#ファイルからすべてのリビジョンを削除します。 def DeleteAll(self): """ Helper function that parse and return revision from file. """ status = False try: self.mainRevision = [None, {}]
ShowOld()#関数の以前のリビジョンに関する情報を表示します。 def ShowOld(self, func=None): """ Function return old revision for given function. """ funcHashOld, funcSourceOld = self._GetOld(func)
ShowNew()#関数の新しいリビジョンに関する情報を表示します。 def ShowNew(self, func=None): """ Function return old revision for given function. """ funcHashNew, funcSourceNew = self._GetNew(func)
Diff()#必要に応じて、関数のリビジョンとdiff出力の比較。 def Diff(self, func=None): """ Checks if given function modified then return tuple with revision's diff: (old_revision, new_revision), otherwise return None. """ funcHashOld, funcSourceOld = self._GetOld(func)
_testFunction()#モジュールの動作をチェックするための偽の関数 def _testFunction(a=None): """ This is fake test function for module. """
if __name__ == '__main__' :()#モジュールを個別に起動するときの使用例 このモジュールの使用例を見るには、Python 3.2.3を使用して実行するだけです。
python FileRevision.py最初の起動時に、スクリプトは、例で実装された偽の関数のリビジョンがないことを検出し、その情報を更新し、リビジョンファイルをクリアし、以前のリビジョンと新しいリビジョンに関する情報を表示します。 次に、.pyファイルの横に、例のリビジョンを含むrevision.txtファイルが作成されます。
したがって、モジュールを使用し、コード改訂ファイルの生成を担当する従業員がいると、テスト機能のセキュリティの度合いが高まります。
今日は以上です。 コメントでの質問や提案をお待ちしています。 ご清聴ありがとうございました!
Posted by Timur Gilmullin、Positive Technologies自動テストグループ