Seleniumで自動テストを迅速かつ効率的に記述するためのツールを作成する

自動化の基本的な構成要素-テスト
ロッド・ジョンソン
画像

私はWebインターフェースをテストする大使ではありませんが、このエッセイはこの分野ですでに経験を積んでいる仲間にとってより役立つ可能性が高いです。

また、初心者にとっても便利です。 最終製品でセレンとのやり取りがどのように編成されているかを確認できるソースコードを提供します。

開発経験がほとんどない状態から、テストを実行するためのプラットフォームを作成した方法、およびプラットフォーム自体について説明します。 私は自分の製品が非常に効果的であるとわかったので、多くの人にとって有用であり、検討の余地があると考えています。

コンセプトの


テストプロセスは情報システムに依存します。

私の概念を覚えておくために、そもそもどのシステムに焦点を当てているかを理解する必要があります。それらは通常、回帰テストを行う際にキーとして設定される特定の線形ビジネスプロセスがあるシステムです。

したがって、srmのようなシステム。 主要なビジネスエンティティはベンダー製品です。 回帰テストを実施する際の重要な考慮事項は、ビジネスプロセスの整合性です。
ビジネスプロセスは、システムへのサプライヤの登録から始まり、商業プロポーザルの作成に進みます-サプライヤへのプロポーザルの検討に関する決定が返されるまで、さまざまなタイプの内部ユーザー(および各ユーザーに固有のインターフェイスがあります)によって実行されるレビュー段階に進みます。

私たちは多くの異なるインターフェースを通過し、ほとんどの場合異なるインターフェースで動作することがわかりました。 実際、それを直接見れば、それはまるでビデオテープを見ているようなものです。 これは、開始と終了のあるプロセスであり、絶対に線形です。分岐はありません。テストを記述するときに、期待される結果が常にわかります。 つまり すでにこの図を見て、テストを多態的にすることは成功しないと結論付けることができます。 これを考慮して、テストを実行するためのプラットフォームを作成するときに、テストを記述する速度を設定する重要な要素を決めました。

私が自分のために設定した概念:

  1. 自動テストはできるだけ早く作成する必要があります。 定性的にこれを達成する場合、信頼性や使いやすさなど、他の側面は自分でやってくるはずです。
  2. テストは宣言的に宣言し、コードとは別に実行する必要があります。 私は別のオプションさえ見ませんでした。 これにより、書き込み速度が向上します。 既製のインタープリターがあれば、私たちのプラットフォームで、後から追加する必要はありません。もう一度コードにアクセスする必要はありません。一般的に、IDEを使用して完成したプラットフォームを忘れることができます。 そのため、テストの保守が簡単になります。 この形式では、書くことを学びやすくなります。なぜなら、 開発スキルは必要ありませんが、マークアップ言語の理解のみが必要です。 この形式では、プロセスのすべての参加者が理解できます。

最初に拒否することにしたこと:

  1. システムをテストフレームワークでラップしないでください。 テストフレームワークなしでプロセスの実行を開始できます。 「あなたは自転車を発明したい!」-多くの人が言うでしょう。 違うと思う。 一般的に使用されるテストフレームワークは、主に内部からコードをテストするために作成されたもので、外部からシステムの外部部分をテストします。 ロードバイクを持っているようなもので、オフロードの山を下る必要があります(失礼ですが、思考の流れが反映されています)。 一般に、ブラックジャックと...でフレームワークを自分で記述します(たとえば、JUnit 5はすでにそのようなタスクにはるかに適合していることは承知していますが)。
  2. セレンのラッパーの使用を拒否。 実際、キーライブラリ自体は小さいです。 その機能の5%を使用する必要があることを理解するには、完全にシャベルで処理するのに数時間かかります。 より少ないコードを書き、トイレに慣れる方法を探してどこにでも。 現代の世界では、この欲求はしばしば不条理につながり、ほとんど常に柔軟性を損ないます(つまり、アーキテクチャフレームワークのケースではなく、「コードを少なくする」アプローチです)。
  3. 結果の美しいプレゼンテーションは必要ありません。 このアイテムを導入したのは、 私はかつてこれに直面していません。 自動テストが完了したら、2つのことを知る必要があります:全体的な結果(正/負)、およびエラーがあったかどうか-正確に。 おそらく、まだ統計を保持する必要があります。 結果の点で他のすべては絶対に不可欠ではありません。 美しいデザインを重要なプラスと考えるか、初期段階でこの美しいデザインに時間を費やすことは余分なショーです。

いくつかの詳細を完全に明確にするために、会社の開発レベルとツールの作成条件についてもう少しお話します。

いくつかの機密事項のため、私は勤務先の会社を開示しません。

当社では、開発が長年にわたってすでに存在しているため、すべてのプロセスが長い間確立されています。 しかし、それらは現在の傾向よりもはるかに遅れています。
ITのすべての代表者は、コードをテストでカバーし、将来の機能の要件を調整する際に自動テスト用のスクリプトを作成する必要があること、柔軟なテクノロジーが時間とリソースを大幅に節約すること、そして単に命を奪い単純化するCIが必要であることを理解しています。 しかし、これまでのところ、これはすべてゆっくりと私たちに届いています...

ソフトウェア品質管理サービスも同様です。「上から」のプロセスを見ると、すべてのテストが手動で実行されます。これが開発プロセス全体の「ボトルネック」です。

組立説明


プラットフォームは、JDK 12を使用してJavaで記述されています

主要インフラツール-Selenium Web Driver、OJDBC

アプリケーションを機能させるには、FireFoxブラウザーバージョン52をPCにインストールする必要があります

アプリケーションビルド構成


画像

アプリケーションでは、3つのフォルダーと2つのファイルが必要です。

BuildKitフォルダー-含まれるもの:


レポートフォルダー-アプリケーションがテストケースを完了すると、レポートが保存されます。 また、エラーが発生した場合にスクリーンショットが保存されるErrorScreensフォルダーも含まれている必要があります。

TestSuiteフォルダー-Webパッケージ、javascript、一連のテストケース(このフォルダーへの入力については、別途詳しく説明します)

•config.propertiesファイル-Oracleデータベースに接続するための構成と、WebDriverWaitに対する明示的な期待値が含まれています

•starter.bat-アプリケーションを起動するファイル(最後にパラメータとしてTestCaseという名前を入力すると、TestCaseを手動で指定せずにアプリケーションを自動的に起動できます)。

アプリケーションの簡単な説明


アプリケーションは、パラメータ(TestCaseという名前)を使用して、またはパラメータなしで起動できます。この場合、テストケースの名前をコンソールに自分で入力する必要があります。

パラメーターなしで実行するbatファイルの一般的な内容の例:start "AutoTest launcher"%cd%\ BuildKit \ jdk-12 \ bin \ java.exe -Xmx768M -jar --enable-preview%cd%\ BuildKit \ SprintAutoTest.jar

アプリケーションの一般的な起動時に、「\ TestSuite \ TestCase」ディレクトリにあるxmlファイルを確認します(サブフォルダーの内容は表示されません)。 この場合、構造の正確性に対するxmlファイルのプライマリ検証が行われ(つまり、xmlマークアップの観点からのすべてのタグが正しい)、「testCaseName」タグに示された名前が取得されます。その後、ユーザーは使用可能なテストの可能な名前の1つを入力するように求められますケース。 入力に誤りがある場合、システムは名前の再入力を求めます。

TestCaseという名前を受け取った後、内部モデルが構築されます。これは、TestCase(テストスクリプト)-Webオブジェクト(要素のストレージ)の束であり、Javaオブジェクトの形式です。 モデルの構築後、TestCase(プログラムの実行可能オブジェクト)が直接構築されます。 TestCaseの構築段階で、2次検証も行われます。TestCaseで指定されたすべてのフォームが関連するWebPackageにあり、アクションで指定されたすべての要素が指定されたページ内のWebPackageにあることを確認します。 (TestCaseおよびWebPackageの構造については、以下で詳しく説明します)

TestCaseのビルド後、スクリプトが直接実行されます

スクリプト操作アルゴリズム(キーロジック)


TestCaseはActionエンティティのコレクションであり、これはイベントエンティティのコレクションです。

テストケース
->リスト{アクション}
->リスト{イベント}

TestCaseが開始されると、アクションが順番に開始されます(各アクションは論理結果を返します)

アクションが開始されると、イベントが順番に開始されます(各イベントは論理結果を返します)

各イベントの結果により、結果が保存されます。

したがって、テストは、すべてのアクションが正常に完了したとき、またはアクションがfalseを返したときに完了します。

*クラッシュメカニズム

なぜなら テスト対象のシステムは古く、エラーではないエラー/バグをキャッチし、一部のイベントは初めて動作しません。プラットフォームには、厳密に線形なテストという上記の概念から逸脱するメカニズムがあります(ただし、厳密に型指定されています)。 このようなエラーをキャッチする場合、最初にケースを繰り返し、追加のアクションを実行してアクションを繰り返すことができます

アプリケーションの最後にレポートが生成され、「\ Reports」ディレクトリに保存されます。 エラーが発生した場合、スクリーンショットが撮られ、「\ Reports \ ErrorScreens」に保存されます

TestSuite Filling


だから、テストの説明。 既に述べたように、実行に必要な主なパラメーターは、実行するテストの名前です。 この名前は、ディレクトリ「/ TestSuite / TestCase」のxmlファイルに保存されます。 すべてのテストスクリプトはこのディレクトリに保存されます。 それらはいくつあってもかまいません。 テストケースの名前は、ファイル名からではなく、ファイル内の「testCaseName」タグから取得されます。

TestCaseは、正確に何を行うかを設定します。 アクション。 xmlファイルのディレクトリ「/ TestSuite / WebPackage」には、すべてのロケーターが保存されます。 つまり すべて最高の伝統-アクションは個別に保存され、Webフォームロケーターは個別に保存されます。

TestCaseは、WebPackage名を「webPackageName」タグにも保存します。

全体像はすでにそこにあります。 実行するには、TestCaseとWebPackageの2つのxmlファイルが必要です。 彼らは束を作ります。 WebPackageは独立しています-識別子はタグ「webPackageName」内の名前です。 したがって、ここに最初のルールがあります-TestCaseとWebPackageの名前は一意でなければなりません。 つまり 繰り返しますが、実際には、テストはTestCaseとWepPackageファイルの束であり、TestCaseで指定されたWebPackage名で接続されています。 実際には、1つのシステムを自動化し、すべてのテストケースを1つのWebPackageにまとめて、すべてのフォームの説明を山積みにします。

論理分解の次の層は、ページオブジェクトなどのパターンに基づいています。

ページオブジェクト
ページオブジェクトは、自動化で最も有用で使用されているアーキテクチャソリューションの1つです。 この設計パターンは、個々のページ要素で作業をカプセル化するのに役立ちます。 ページオブジェクトは、テスト対象のアプリケーションのページをオブジェクトとしてシミュレートします。

ロジックと実装の分離

テストロジック(チェック対象)とその実装(チェック方法)には大きな違いがあります。 テストシナリオの例:「ユーザーが間違ったユーザー名またはパスワードを入力し、ログインボタンを押し、エラーメッセージを受け取ります。」 このスクリプトはテストのロジックを記述しますが、実装にはページ上の入力フィールドの検索、入力、エラーのチェックなどのアクションが含まれます。 また、たとえば、エラーメッセージの表示方法が変更されても、テストスクリプトに影響しない場合は、誤ったデータを入力し、ログインボタンを押してエラーを確認する必要があります。 ただし、これはテストの実装に直接影響します。エラーメッセージを受信して​​処理するメソッドを変更する必要があります。 テストのロジックを実装から分離することにより、自動テストはより柔軟になり、原則として保守が容易になります。

*! このアーキテクチャのアプローチが完全に適用されたとは言えません。 テストシナリオの説明をページごとに分解するだけです。これにより、テストをより速く記述し、すべてのページに自動チェックを追加し、ロケーターの正しい説明を刺激し(異なるページで同じではないように)、テストの「美しい」論理構造を構築します。 プラットフォーム自体は、「クリーンアーキテクチャ」の原則に基づいて実装されています

次に、WebPackageとTestCaseの構造を詳しく説明しないようにします。 彼らのために、WebPackage用のDTDスキーマとTestCase用のXSD 1.1を作成しました。

! 重要な


DTDおよびXSDスキームを維持することにより、迅速なテスト作成の概念が実装されます。

WebPackageとTestCaseを直接記述する場合、タグの自動生成機能を備えた組み込みのリアルタイムDTDおよびXSD検証機能を備えたxml Editorを使用する必要があります。これにより、自動テストの記述プロセス自体が大幅に自動化されます(必要なすべてのタグが自動的に置き換えられ、属性値のドロップダウンリストが表示されます)可能な値は、対応するタグが生成されるイベントのタイプに応じて)

これらのスキームがxmlファイル自体に「ねじ込まれ」ている場合、特別な環境を使用すると、xmlファイルの構造の正確さを忘れることがあります。 私が選んだのはoXygen XLM Editorでした。 繰り返しますが、このようなプログラムを使用しないと、書き込み速度の本質を理解できません。 アイデアはこれにはあまり適していません。 TestCaseの鍵となるXSD 1.1の「代替」コンストラクトは処理しません。

Webpackage


WebPackaege-ディレクトリ「\ TestSuite \ WebPackage」にあるWebフォームの要素を記述するxmlファイル。 (好きなだけファイルを作成できます。ファイルの名前は何でも構いません-内容だけが重要です)。

DTD(ドキュメントの冒頭に挿入):
<!DOCTYPE webPackage [ <!ELEMENT webPackage (webPackageName, forms)> <!ELEMENT webPackageName (#PCDATA)> <!ELEMENT forms (form+)> <!ELEMENT form (formName, elements+)> <!ELEMENT formName (#PCDATA)> <!ELEMENT elements (element+)> <!ELEMENT element (name, locator)> <!ATTLIST element type (0|1|2|3|4|5|6|7) #REQUIRED> <!ATTLIST element alwaysVisible (0|1) #IMPLIED> <!ELEMENT name (#PCDATA)> <!ELEMENT locator (#PCDATA)> <!ATTLIST locator type (1|2) #IMPLIED> ]> 


一般的に、おおよそ
 <webPackage> <webPackageName>_</webPackageName> <forms> <form> <formName>______</formName> <elements> <element type="2" alwaysVisible="1"> <name>_</name> <locator type="2">.//div/form/div/div/form/table/tbody/tr/td[text()=""]/following-sibling::td/input</locator> </element> <element type="2"> <name>__</name> <locator>.//div/form/div/div/form/table/tbody/tr/td[text()=""]/following-sibling::td/input</locator> </element> ....... </elements> </form> ....... </forms> </webPackage> 


既に述べたように、要素がヒープ内にないように-すべてがWebフォームに従って分解されます

キーエンティティは
 <element> 

要素タグには2つの属性があります。


type属性は必須であり、要素のタイプを指定します。 プラットフォームで、バイトタイプを設定します

現時点では、特にプラットフォームで自分のために、次のタイプを実装しています。

•0-機能的な意味はありません。通常、何らかの種類の碑文です。
•1-ボタン(ボタン)
•2-入力フィールド(入力)
•3-チェックボックス(checkBox)
•4-ドロップダウンリスト(選択)-実際には実装されていませんが、その場所を残しました
•5-srmドロップダウンリストの場合:名前を記述し、値が表示されるまで待機します-特定のxpathテンプレートに従って選択します-システム固有のタイプ
•6-srm select-検索などの一般的な機能で使用されます。 -私のシステム専用の入力

alwaysVisible属性(オプション)は、要素が常にフォームに存在するかどうかを示し、アクションの初期/最終検証中に使用できます(つまり、自動モードでは、フォームを開いたときに、フォーム上に常にあるすべての要素が含まれていることを確認できます)フォーム、これらの要素はすべて消えました)

可能な値:


オプションのオプションのtype属性は、ロケータータグで実装されます

可能な値:


テストケース


TestCase-テストスクリプト自体を記述するxmlファイルは、「\ TestSuite \ TestCase」ディレクトリにあります(好きなだけファイルを作成できます。ファイル名は任意です-内容のみが重要です)。

XSD回路:
 <xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.1"> <xs:element name="testCase"> <xs:complexType> <xs:sequence> <xs:element name="testCaseName" type="xs:string"/> <xs:element name="webPackageName" type="xs:string"/> <xs:element name="actions" type="actionsType"/> </xs:sequence> </xs:complexType> </xs:element> <xs:complexType name="actionsType"> <xs:sequence> <xs:element name="action" type="actionType" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <xs:complexType name="actionType"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="orderNumber" type="xs:positiveInteger"/> <xs:element name="runConfiguration" type="runConfigurationType"/> </xs:sequence> </xs:complexType> <xs:complexType name="runConfigurationType"> <xs:sequence> <xs:element name="formName" type="xs:string"/> <xs:element name="repeatsOnError" type="xs:positiveInteger" minOccurs="0"/> <xs:element name="events" type="eventsType"/> <xs:element name="exceptionBlock" type="eventsType" minOccurs="0"/> </xs:sequence> <xs:attribute name="openValidation" use="required"> <xs:simpleType> <xs:restriction base="xs:byte"> <xs:enumeration value="1"/> <xs:enumeration value="0"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="closeValidation" use="required"> <xs:simpleType> <xs:restriction base="xs:byte"> <xs:enumeration value="1"/> <xs:enumeration value="0"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:complexType> <xs:complexType name="eventBaseType"> <xs:sequence> <xs:element name="orderNumber" type="xs:positiveInteger"/> </xs:sequence> <xs:attribute name="type" use="required"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:enumeration value="goToURL"/> <xs:enumeration value="checkElementsVisibility"/> <xs:enumeration value="checkElementsInVisibility"/> <xs:enumeration value="fillingFields"/> <xs:enumeration value="clickElement"/> <xs:enumeration value="dbUpdate"/> <xs:enumeration value="wait"/> <xs:enumeration value="scrollDown"/> <xs:enumeration value="userInput"/> <xs:enumeration value="checkInputValues"/> <xs:enumeration value="checkQueryResultWithUtilityValue"/> <xs:enumeration value="checkFieldsPresenceByQueryResult"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="invertResult" use="optional" default="0"> <xs:simpleType> <xs:restriction base="xs:byte"> <xs:enumeration value="1"/> <xs:enumeration value="0"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="hasExceptionBlock" use="optional" default="0"> <xs:simpleType> <xs:restriction base="xs:byte"> <xs:enumeration value="1"/> <xs:enumeration value="0"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:complexType> <xs:complexType name="eventsType"> <xs:sequence> <xs:element name="event" type="eventBaseType" maxOccurs="unbounded"> <xs:alternative test="@type='goToURL'" type="eventGoToURL"/> <xs:alternative test="@type='checkElementsVisibility'" type="eventCheckElementsVisibility"/> <xs:alternative test="@type='checkElementsInVisibility'" type="eventCheckElementsVisibility"/> <xs:alternative test="@type='fillingFields'" type="eventFillingFields"/> <xs:alternative test="@type='checkInputValues'" type="eventFillingFields"/> <xs:alternative test="@type='clickElement'" type="eventClickElement"/> <xs:alternative test="@TYPE='dbUpdate'" type="eventRequest"/> <xs:alternative test="@type='wait'" type="utilityValueInteger"/> <xs:alternative test="@type='scrollDown'" type="eventClickElement"/> <xs:alternative test="@type='userInput'" type="eventClickElement"/> <xs:alternative test="@type='checkQueryResultWithUtilityValue'" type="eventRequestWithValue"/> <xs:alternative test="@type='checkFieldsPresenceByQueryResult'" type="eventRequestWithValue"/> </xs:element> </xs:sequence> </xs:complexType> <!--   EVENTS --> <xs:complexType name="eventGoToURL"> <xs:complexContent> <xs:extension base="eventBaseType"> <xs:sequence> <xs:element name="url" type="xs:anyURI"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="eventCheckElementsVisibility"> <xs:complexContent> <xs:extension base="eventBaseType"> <xs:sequence> <xs:element name="fields" type="fieldType"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="eventFillingFields"> <xs:complexContent> <xs:extension base="eventBaseType"> <xs:sequence> <xs:element name="fields" type="fieldTypeWithValue"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="eventClickElement"> <xs:complexContent> <xs:extension base="eventBaseType"> <xs:sequence> <xs:element name="elementName" type="xs:string"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="eventRequest"> <xs:complexContent> <xs:extension base="eventBaseType"> <xs:sequence> <xs:element name="dbRequest" type="xs:string"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="utilityValueInteger"> <xs:complexContent> <xs:extension base="eventBaseType"> <xs:sequence> <xs:element name="utilityValue" type="xs:positiveInteger"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="eventRequestWithValue"> <xs:complexContent> <xs:extension base="eventBaseType"> <xs:sequence> <xs:element name="dbRequest" type="xs:string"/> <xs:element name="utilityValue" type="xs:string"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <!--   EVENTS --> <xs:complexType name="fieldType"> <xs:sequence> <xs:element name="field" maxOccurs="unbounded"> <xs:complexType> <xs:choice> <xs:element name="element" type="xs:string"/> <xs:element name="xpath" type="xs:string"/> </xs:choice> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> <xs:complexType name="fieldTypeWithValue"> <xs:sequence> <xs:element name="field" maxOccurs="unbounded"> <xs:complexType> <xs:sequence> <xs:element name="element" type="xs:string"/> <xs:element name="value" type="valueType"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> <xs:complexType name="valueType"> <xs:complexContent> <xs:extension base="xs:anyType"> <xs:attribute name="type" use="optional" default="1"> <xs:simpleType> <xs:restriction base="xs:byte"> <xs:enumeration value="1"/> <xs:enumeration value="2"/> <xs:enumeration value="3"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> </xs:schema> 


一般的なビュー:
 <!DOCTYPE testCase SYSTEM "./TestSuite/TestCase/entities.dtd" []> <testCase xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="testShema.xsd"> <testCaseName>__testCase</testCaseName> <webPackageName>_webPackage__webPackageName</webPackageName> <actions> <action> <name>          </name> <orderNumber>10</orderNumber> <runConfiguration openValidation="1" closeValidation="1"> <formName>______</formName> <events> <event type="goToURL"> <orderNumber>10</orderNumber> <url>&srmURL;</url> </event> ....... </events> </runConfiguration> </action> ....... </actions> </testCase> 


この行では、XMLエディターに表示されるようにxsdスキームを固定する方法を確認できます。

 <testCase xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="testShema.xsd"> 

TestCaseでは、同じディレクトリ(拡張子.dtdのファイル)に個別に保存されているDTDエンティティも使用します。 その中に、ほぼすべてのデータ(定数)を格納します。 また、新しいテストを起動するためにロジックを構築しました。テスト中、新しい一意のエンティティが作成され、新しい宇宙船が登録され、このファイルの1桁を変更するだけで十分でした。

その構造は非常に単純です。例を挙げます。
 <?xml version="1.0" encoding="UTF-8"?> <!ENTITY mainNumber '040'> <!ENTITY mail '@mail.ru'> <!ENTITY srmURL 'https://srm-test.ru'> 


このような定数は、次のようにタグ値に挿入されます。

 <url>&srmURL;</url> 

-組み合わせることができます。

推奨事項 -testCaseを作成するときは、ドキュメント内でこれらのDTDエンティティを指定し、すべてが安定して機能した後、別のファイルに転送する必要があります。 私のxmlエディターはこれに問題があります-DTDを見つけることができず、XSDを考慮しません

testCase

testCase-最も親タグに含まれるもの:


行動

含まれるもの:


runConfiguration

含まれるもの:


出来事

最小構造単位-このエンティティは、実行されるアクションを示します

各イベントは特別であり、一意のタグと属性を持つことができます。

基本タイプには以下が含まれます。


*! 予想されるエラーを説明するメカニズム
私が最初にそれを使用した場所と、それを機能させるために何をすべきかという些細な例を挙げましょう。

ケース:キャプチャ入力。 この瞬間を自動化することはできませんでした。つまり、これまでのところロボットのクラッシュチェックはクラッシュしました。キャプチャテストサービスを書いてくれませんでした(ただし、認識のためにニューラルネットワークを作成する方が簡単です))。 この場合、コントロールイベントを作成します。このイベントでは、要素がないことを確認します-不正なコントロールコードに関する通知、hasExceptionBlock属性を設定します。 以前は、いくつかの繰り返し(5)を実行できるようにアクションを要求しましたが、結局、exceptionBlockを作成しました。

私の文脈からの例。

イベントの登録方法は次のとおりです。

 <event type="checkElementsInVisibility" hasExceptionBlock="1"> <orderNumber>57</orderNumber> <fields> <field> <element>___</element> </field> </fields> </event> 

そして、ここでexceptionBlock after events

  <exceptionBlock> <event type="clickElement"> <orderNumber>10</orderNumber> <elementName>_____</elementName> </event> </exceptionBlock> 

そして、はい、1ページのアクションはいくつかのアクションに分解できます。

+ configで2つのパラメーターに気づいた人:defaultTimeOutsForWebDriverWait、lowTimeOutsForWebDriverWait。 だからこそ彼らはそうです。 なぜなら 私はシングルトンにWebドライバー全体を持っていますが、毎回新しいWebDriverWaitを作成したくはありませんでしたが、1つの高速ドライバーを持っていますが、エラーの場合です明示的な待機)-さて、あなたは同意する必要があります、メッセージが出てきていないことを確認するために1分待ってください。 まあ、どちら側に固執しないこの状況は松葉杖が必要です-私はそうすることにしました。

イベントの種類


ここでは、システムのほとんどすべてをテストできるスカウトセットなど、イベントの最小限のセットを提供します。

そして、イベントが何であり、どのように構築されるかを理解するのはコードにとってスムーズです。 コードは基本的にフレームワークを実装します。 DataBaseWrapperとSeleniumWrapperの2つのクラスがあります。 これらのクラスは、インフラストラクチャコンポーネントとの相互作用を記述し、プラットフォームの機能も反映します。 SeleniumWrapperを実装するインターフェイスを提供します

 package logic.selenium; import models.ElementWithStringValue; import models.webpackage.Element; import org.openqa.selenium.WebElement; public interface SeleniumService { void initialization(boolean webDriverWait); void nacigateTo(String url); void refreshPage(); boolean checkElementNotPresent(Element element); WebElement findSingleVisibleElement(Element element); WebElement findSingleElementInDOM(Element element); void enterSingleValuesToWebField(ElementWithStringValue element); void click(Element element); String getInputValue(Element element); Object jsReturnsValue(String jsFunction); //Actions actions void doubleClick(Element element); void moveMouseToElement(Element element); void pressKey(CharSequence charSequence); void getScreenShot(String storage); } 

セレンのすべての機能について説明し、プラットフォームの機能をオーバーレイします。実際、主な機能は「enterSingleValuesToWebField」メソッドです。 WebPackageで要素のタイプを指定することに注意してください。 したがって、フィールドに入力するときにこのタイプにどのように反応するかをここに記述します。 1回書いて忘れます。 上記の方法は、まず自分で修正する必要があります。 たとえば、現在有効なタイプ5および6は、私のシステムにのみ適しています。 そして、あなたがフィルターのようなものを持っていて、たくさんのフィルターをかける必要があり、それが典型的である場合(あなたのウェブアプリケーションで)、それを使用するには、最初にフィールド上にマウスを移動し、いくつかのフィールドが表示されるのを待って、いくつかに切り替え、待ってください何かがあり、そこに行って入力してください...愚かなアクションのメカニズムを1回指定し、スイッチ構造内でこれにユニークなタイプを与えてください-気にしないでください-あなたはすべての同様のアプリケーションフィルターの多態性メソッドを取得します。

そのため、パッケージ「package logic.testcase.events」には、イベントの一般的なアクションを記述する抽象クラスがあります。 独自のイベントを作成するには、新しいクラスを作成し、この抽象クラスから継承する必要があります。キットには既にdataBaseServiceとseleniumServiceがあります。そして、必要なデータとその処理方法を決定します。 そのようなもの。 それに応じて、新しいイベントを作成した後、TestCaseActionFactoryファクトリクラスと、可能であればXSDスキームを完了する必要があります。 さて、新しい属性が追加された場合-モデル自体を変更します。 実際、非常に簡単で高速です。

だから、スカウトキット。

goToURL-通常は最初のアクション-指定されたリンクをクリックします

例:
 <event type="goToURL"> <orderNumber>10</orderNumber> <url>testURL</url> </event> 


fillFields-指定された要素を埋める

特別なタグ:



例:
 <event type="fillingFields"> <orderNumber>10</orderNumber> <fields> <field> <element>test</element> <value>test</value> </field> </fields> </event> 


checkElementsVisibility-指定された要素がフォーム上に存在することを確認します(つまり、DOMだけでなく、表示されます)。 field属性では、WebPackageの要素または直接xpathのいずれかを指定できます

例:
 <event type="checkElementsVisibility"> <orderNumber>10</orderNumber> <fields> <field> <element>test</element> </field> <field> <xpath>test</xpath> </field> </fields> </event> 


checkElementsInVisibility - checkElementsVisibilityに似ていますが、逆も同様です。

clickElement-指定された要素をクリックします

例:
 <event type="clickElement"> <orderNumber>10</orderNumber> <elementName>test</elementName> </event> 


checkInputValues-入力値を確認します

例:
 <event type="checkInputValues"> <orderNumber>10</orderNumber> <fields> <field> <element>test</element> <value>test</value> </field> </fields> </event> 


dbUpdate-データベースで更新を実行します( oXygenはdbUpdateタイプの1つのイベントに奇妙な反応をします-どうすればいいのかわかりませんし、理由もわかりません

例:
 <event type="dbUpdate"> <orderNumber>10</orderNumber> <dbRequest>update - </dbRequest> </event> 


CheckQueryResultWithUtilityValue-データベースからの値を使用して、ユーザーが入力した値を確認します

例:
 <event type="checkQueryResultWithUtilityValue"> <orderNumber>10</orderNumber> <dbRequest>select ...</dbRequest> <utilityValue>test</utilityValue> </event> 


checkFieldsPresenceByQueryResult-パターンごとに xpathでフォーム上の要素の存在を確認します。 目的のパターンが指定されていない場合、検索はパターン.//* [text()[contains(normalize-space(。)、 "$")]]に従って行われます。 独自のパターンを記述する場合、データベースから値を配置する場所に「$」を指定する必要があります。 私のシステムにはいわゆるグリッドがあり、そこには通常、ある種のビューから形成される値があります。 このようなグリッドをテストするこのイベント

例:
 <event type="checkFieldsPresenceByQueryResult"> <orderNumber>10</orderNumber> <dbRequest>test</dbRequest> <utilityValue></utilityValue> </event> 


待機 -すべてが単純です-指定されたミリ秒数待機します。 残念ながら、これは松葉杖であると考えられていますが、私は確かに言うでしょう-時にはそれなしで行うことは不可能です

例:
 <event type="wait"> <orderNumber>10</orderNumber> <utilityValue>1000</utilityValue> </event> 


scrollDown-指定された要素から下にスクロールします。 これは次のように行われます。指定された要素をクリックし、「PgDn」キーを押します。 下にスクロールしなければならなかった私の場合、それはうまく機能します:

例:
 <event type="scrollDown"> <orderNumber>10</orderNumber> <elementName>test</elementName> </event> 


userInput-指定された要素に値を入力します。 私のオートメーションで唯一の半自動デバイスで、キャプチャにのみ使用されます。 値を入力する要素が示されています。 値はポップアップダイアログボックスに入力されます。

例:
 <event type="userInput"> <orderNumber>10</orderNumber> <elementName>capch_input</elementName> </event> 


コードについて


そこで、ボブおじさんのクリーンアーキテクチャの原則に従ってプラットフォームを作成しようとしました。

パッケージ:

アプリケーション-初期化と起動+構成とレポート(Reportクラスについてscられないでください-これが最も簡単に実行され、できるだけ早く実行されます)

ロジック-SeleniumとDBの主要なロジック+サービス。 イベントがあります。

モデル-XMLのPOJOおよびすべてのヘルパーオブジェクトクラス

utils-セレンとdbのシングルトン

コードを実行するには、jdk 12をダウンロードし、どこでも指定してチップがオンになるようにする必要があります。 アイデアでは、これはプロジェクト構造->モジュールとプロジェクトを介して行われます。 また、Mavenランナーについても忘れないでください。 そして、batファイルで起動するときに、-enable-previewを追加します。例がありました。

さて、すべてを起動するには、JDKでojdbcドライバーをダウンロードし、dzharnikを「SprintAutoTest \ src \ lib」ディレクトリにドロップする必要があります。私はそれを提供しません、なぜなら現在、そこのOracleではすべてが深刻です-ダウンロードするには登録する必要がありますが、誰もが何らかの方法で対処するはずです(まあ、すべてのフォルダが作成されていることを確認してください、そうでなければレポートは保存されません)

まとめ


そのため、テストランチャーがあり、テストの作成が非常に高速です。 1週間の作業中に、ロボットによって5〜6分で実行される1.5時間の手動作業を自動化できました。これらは、連結されたテストケースの約3700行と記述された830要素(4800行以上)です。数値は大まかなため、測定されていませんが、自動化に従事している人は、これが特にロボットにやさしいシステムにとって非常に高い指標であることを理解する必要があります。同時に、すべてをテストします-ビジネスロジック、満たされた属性の正確さについていくつかの否定的なテストを実行する方法に沿って、ボーナスとして、私は怠けていないすべてのWebフォームをチェックし、すべての機能および主要な要素を説明します、それらは独立して必要です私にとってかどうか(小さな余談-私は主にテストを書くときだけcloseValidationを使用します。安定しており、ロケーターが交差していないことが明らかな場合、すべてのアクションでロケーターをオフにして、プロセスを高速化します)。

一見、多くのxml行があるように見えますが、実際には半自動で生成され、直接入力されたパラメーターでのみエラーが発生します(実際には、2つのレベルの検証があります-最初はスキームのxml、2番目はTestCaseの開始時に指定されたフォームと要素の存在を確認します)。

マイナス-テストの明確な境界はありません。そのため、それらは欠落しており、これはテストではなく単なるマクロランチャーであると非難することができます。私はこう言います:

プラットフォームでは、テストは概念的にいくつかの観点からいくつかの抽象化レベルに分けられます:


私のアプローチを何かと比較すると、たとえば人気のあるキュウリとBDDのコンセプトのマイナス面は、私にとってより重要です(正確に私のシステムのようなものをテストするとき):


私がしたいこと、考えたいことから、しかし私の手はまだ届いていません:


まあ、それがすべてです。githubへの参照:ソースコードを同封します

私は建設的な批判を非常にうれしく思います。このプロジェクトが本当に役立つことを願っています。

Source: https://habr.com/ru/post/J450726/


All Articles