はじめに
Angular.orgのスローガンが誇らしげに説明しているように:
Angularは、HTMLがアプリケーション用に設計されていた場合 、それが無料の翻訳で次のように聞こえる場合、HTMLになります。Angularは、HTMLのことです。 AngularJSは、テスト可能なように一から設計されました。 しかし、多くのSelenium開発者は既存のJavaまたはC#コードベースとスキルを引き続き使用したいと考えていますが、AngularJS SPAおよびMVVM Webアプリケーションのテストに切り替えると、主要なAngularJSアプリケーションテストツールであるProtractorもJavaScriptで記述されます。
幸いなことに、Protractorは他の言語に簡単に移植できます-Selenium WebDriverがベースにしているJsonWireプロトコルの小さなサブセット、つまり1つのインターフェースを使用します。
短期間で、 protractor-netプロジェクトが追加され、C#のJavascriptから既存のProtractorメソッドhttps://github.com/angular/protractor/blob/master/lib/clientsidescripts.jsのポートと、同じタスクを実行する別のプロジェクトで表されました。 Javaから。
テストのために、サイトhttp://www.way2automation.comが選択されました。このサイトには、特に、AngularJSのプロジェクトがあります
http://www.way2automation.com/angularjs-protractor/banking
テストは、残高の確認、アカウントの作成、支払いなどを行うためのXYZ銀行の「クライアント」および「マネージャー」の「標準」アクションです。 -これにより、利用可能なすべての方法を説明できました。 テスト呼び出しはC#プロジェクトとJavaから行われます
コード例
C#
「クライアント」が入り、口座を選択し、金額を入力し、取引が終了すると、残高を確認します(資金を引き出すテストもあります-ここには表示されていません。アーカイブを参照してください)。
[テストフィクスチャ] パブリッククラスWay2AutomationTests { private StringBuilder validationErrors = new StringBuilder(); プライベートIWebDriverドライバー。 プライベートNgWebDriver ngDriver; プライベートWebDriverWait待機; プライベートIAlertアラート。 プライベート文字列alert_text; プライベートRegex theReg; private MatchCollection theMatches; private Match theMatch; プライベートCapture theCapture; private int wait_seconds = 3; private int highlight_timeout = 100; プライベートアクションアクション。 private String base_url = "http://www.way2automation.com/angularjs-protractor/banking"; [TestFixtureSetUp] public void SetUp() { driver = new FirefoxDriver(); driver.Manage()。Timeouts()。SetScriptTimeout(TimeSpan.FromSeconds(60)); ngDriver =新しいNgWebDriver(ドライバー); wait = new WebDriverWait(ドライバー、TimeSpan.FromSeconds(wait_seconds)); アクション=新しいアクション(ドライバー); } [セットアップ] public void NavigateToBankingExamplePage() { driver.Navigate()。GoToUrl(base_url); ngDriver.Url = driver.Url; } [TestFixtureTearDown] public void TearDown() { 試してみる { driver.Close(); driver.Quit(); } catch(例外){} Assert.IsEmpty(verificationErrors.ToString()); } [テスト] public void ShouldDeposit() { ngDriver.FindElement(NgBy.ButtonText( "顧客ログイン"))。();をクリックします。 ReadOnlyCollection <NgWebElement> ng_customers = ngDriver.FindElement(NgBy.Model( "custId"))。FindElements(NgBy.Repeater( "顧客の顧客")); //ログインする顧客を選択します ng_customers.First(cust => Regex.IsMatch(cust.Text、 "Harry Potter"))。();をクリックします。 ngDriver.FindElement(NgBy.ButtonText( "Login"))。クリック(); ngDriver.FindElement(NgBy.Options(「アカウントのアカウントのアカウント」))。();をクリックします。 NgWebElement ng_account_number_element = ngDriver.FindElement(NgBy.Binding( "accountNo")); int account_id = 0; int.TryParse(ng_account_number_element.Text.FindMatch(@ "(?<result> \ d +)$")、out account_id); Assert.AreNotEqual(0、account_id); int account_amount = -1; int.TryParse(ngDriver.FindElement(NgBy.Binding( "amount"))。Text.FindMatch(@ "(?<result> \ d +)$")、out account_amount); Assert.AreNotEqual(-1、account_amount); ngDriver.FindElement(NgBy.PartialButtonText( "Deposit"))。クリック(); //コアセレン wait.Until(ExpectedConditions.ElementExists(By.CssSelector( "form [name = 'myForm']")))); NgWebElement ng_form_element = new NgWebElement(ngDriver、driver.FindElement(By.CssSelector( "form [name = 'myForm']")))); NgWebElement ng_deposit_amount_element = ng_form_element.FindElement(NgBy.Model( "amount")); ng_deposit_amount_element.SendKeys( "100"); NgWebElement ng_deposit_button_element = ng_form_element.FindElement(NgBy.ButtonText( "Deposit")); ngDriver.Highlight(ng_deposit_button_element); ng_deposit_button_element.Click(); //ステータスメッセージを検査します var ng_message_element = ngDriver.FindElement(NgBy.Binding( "message")); StringAssert.Contains( "Deposit Successful"、ng_message_element.Text); ngDriver.Highlight(ng_message_element); //金額を再読み取りします int updated_account_amount = -1; int.TryParse(ngDriver.FindElement(NgBy.Binding( "amount"))。Text.FindMatch(@ "(?<result> \ d +)$")、out updated_account_amount); Assert.AreEqual(updated_account_amount、account_amount + 100); }
Java
「クライアント」はログインし、アカウントを選択し、トランザクションを監視し、「クレジット」レコードを見つける方法を知っています。
@テスト public void testListTransactions()throws Exception { //顧客ログイン ngDriver.findElement(NgBy.buttonText( "カスタマーログイン"))。クリック(); //トランザクションのある顧客/アカウントを選択 assertThat(ngDriver.findElement(NgBy.input( "custId"))。getAttribute( "id")、equalTo( "userSelect")); 列挙<WebElement> customers = Collections.enumeration(ngDriver.findElement(NgBy.model( "custId"))。FindElements(NgBy.repeater( "顧客の顧客"))); while(customers.hasMoreElements()){ WebElement next_customer = customers.nextElement(); if(next_customer.getText()。indexOf( "Hermoine Granger")> = 0){ System.err.println(next_customer.getText()); next_customer.click(); } } NgWebElement login_element = ngDriver.findElement(NgBy.buttonText( "Login")); assertTrue(login_element.isEnabled()); login_element.click(); 列挙<WebElement> accounts = Collections.enumeration(ngDriver.findElements(NgBy.options(「Accountsのアカウントのアカウント」))); while(accounts.hasMoreElements()){ WebElement next_account = accounts.nextElement(); if(Integer.parseInt(next_account.getText())== 1001){ System.err.println(next_account.getText()); next_account.click(); } } //トランザクションを検査します NgWebElement ng_transactions_element = ngDriver.findElement(NgBy.partialButtonText( "Transactions")); assertThat(ng_transactions_element.getText()、equalTo( "Transactions")); ハイライト(ng_transactions_element); ng_transactions_element.click(); wait.until(ExpectedConditions.visibilityOf(ngDriver.findElement(NgBy.repeater( "tx in transaction"))。getWrappedElement())); イテレータ<WebElement> ng_transaction_type_columns = ngDriver.findElements(NgBy.repeaterColumn( "tx in transaction"、 "tx.type"))。Iterator(); while(ng_transaction_type_columns.hasNext()){ WebElement列=(WebElement)ng_transaction_type_columns.next(); if(column.getText()。isEmpty()){ 休憩; } if(column.getText()。equalsIgnoreCase( "クレジット")){ ハイライト(列); } } }
インタラクティブなテストの場合、ポート
4444
ローカルにSeleniumノードとハブを実行する価値があります
@BeforeClass public static void setup()throws IOException { DesiredCapabilities機能=新しいDesiredCapabilities( "firefox"、 ""、Platform.ANY); FirefoxProfile profile = new ProfilesIni()。GetProfile( "default"); capabilities.setCapability( "firefox_profile"、プロファイル); seleniumDriver =新しいRemoteWebDriver(新しいURL( "http://127.0.0.1-00-00444/wd/hub")、機能); { seleniumDriver.manage()。window()。setSize(新しいディメンション(600、800)); seleniumDriver.manage()。timeouts() .pageLoadTimeout(50、TimeUnit.SECONDS) .implicitlyWait(20、TimeUnit.SECONDS) .setScriptTimeout(10、TimeUnit.SECONDS); } catch(例外ex){ System.out.println(ex.toString()); } ngDriver =新しいNgWebDriver(seleniumDriver); }
ビルド用
@BeforeClass public static void setup()throws IOException { seleniumDriver = new PhantomJSDriver(); wait = new WebDriverWait(seleniumDriver、flexible_wait_interval); wait.pollingEvery(wait_polling_interval、TimeUnit.MILLISECONDS); アクション=新しいアクション(seleniumDriver); ngDriver =新しいNgWebDriver(seleniumDriver); }
特徴
同期する
動的ページの場合、多様であることに加えて/ではなく、個々のページ要素がどのように見えるか、またはコアSeleniumによって提供されるそれらに何が起こるかを確認するための非常に読みにくい方法があります。
elementSelectionStateToBe ( By locator, boolean selected)
指定されたアイテムが選択されているかどうかを確認します
elementToBeClickable ( By locator)
利用可能なアイテム
stalenessOf ( WebElement element)
要素がDOMにアタッチされなくなるまで
textToBePresentInElementLocated ( By locator, java.lang.String text)
テキストは、このロケーターが見つける要素に存在します
textToBePresentInElementValue ( By locator, java.lang.String text)
テキストは、このロケーターが見つける要素の選択された属性に存在します
visibilityOfAllElementsLocatedBy ( By locator)
ロケーターと一致するすべての要素がWebページに表示されることを確認します
(ドキュメントhttps://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.htmlから抜粋)、 分度器は直接Angular を呼び出します
public boolean isSelected(){ this.ngDriver.WaitForAngular(); return this.element.isSelected(); } public void WaitForAngular(){ if(!this.IgnoreSynchronization){ this.jsExecutor.executeAsyncScript(ClientSideScripts.WaitForAngular、this.rootElement); } }
送る
var el = document.querySelector(arguments [0]); var callback = arguments [1]; angular.element(el).injector()。get( '$ browser')。notifyWhenNoOutstandingRequests(コールバック);
および/または
var rootSelector = arguments [0]; var callback = arguments [1]; if(window.getAngularTestability){ window.getAngularTestability(el).whenStable(コールバック); 帰る }
このメソッドは、「コア」メソッドが呼び出される前に、ページ要素を持つすべての標準アクションから呼び出されます。次に例を示します。
パブリックブール表示 { { this.ngDriver.WaitForAngular(); return this.element.Displayed; } }
その結果、テスト対象のサイトとテストスクリプトは、追加の労力なしで適切に同期されます。
テスト作成
目的の要素のCSSセレクターとXPathをコピーする代わりに、テスト開発者はページテンプレートを調べます
www.way2automation.com/angularjs-protractor/banking/depositTx.html
<span class = "error" ng-show = "message"> {{message}} </ span> <br>
そして彼女のコントローラー
www.way2automation.com/angularjs-protractor/banking/depositController.js
if(txObj.success){ $ scope.message = "Deposit Successful"; } else { $ scope.message = "問題が発生しました。もう一度やり直してください。"; }
確認するには:
//メッセージを検査します var ng_message = ngDriver.FindElement(NgBy.Binding( "message")); StringAssert.Contains( "Deposit Successful"、ng_message.Text); ngDriver.Highlight(ng_message);
追加機能
分度器は、を見つけるだけでなく、関心のあるオブジェクトを計算することもできます。
[テスト] public void ShouldEvaluateTransactionDetails() { ngDriver.FindElement(NgBy.ButtonText( "顧客ログイン"))。();をクリックします。 //トランザクションのある顧客/アカウントを選択します ngDriver.FindElement(NgBy.Model( "custId"))。FindElements(NgBy.Repeater( "顧客のカスト"))。最初(cust => Regex.IsMatch(cust.Text、 "Hermoine Granger"))をクリックします( ); ngDriver.FindElement(NgBy.ButtonText( "Login"))。クリック(); ngDriver.FindElements(NgBy.Options( "アカウントのアカウントのアカウント"))。最初(アカウント=> Regex.IsMatch(アカウント。テキスト、 "1001"))。クリック(); //トランザクションに切り替えます NgWebElement ng_transaction_list_button = ngDriver.FindElement(NgBy.PartialButtonText( "Transactions")); StringAssert.Contains( "Transactions"、ng_transaction_list_button.Text); ngDriver.Highlight(ng_transaction_list_button); ng_transaction_list_button.Click(); //トランザクション情報が読み込まれてレンダリングされるのを待ちます wait.Until(ExpectedConditions.ElementExists(NgBy.Repeater( "tx in transaction"))); // Evaluateを使用して最初のいくつかのトランザクションを調べます ReadOnlyCollection <NgWebElement> ng_transactions = ngDriver.FindElements(NgBy.Repeater( "tx in transaction")); int cnt = 0; foreach(ng_transactionsのNgWebElement ng_current_transaction){ if(cnt ++> 5){break; } StringAssert.IsMatch( "(?I:credit | debit)"、ng_current_transaction.Evaluate( "tx.type")。ToString()); StringAssert.IsMatch(@ "(?:\ D +)"、ng_current_transaction.Evaluate( "tx.amount")。ToString()); // 'tx.date'は、C言語のUniversalSortableDateTimePatternに似たJavascript UTC形式です# var transaction_date = ng_current_transaction.Evaluate( "tx.date"); StringAssert.IsMatch(@ "(?:\ D {4} \-\ d {2} \-\ d {2} T \ d {2}:\ d {2}:\ d {2}。\ D { 3} Z) "、transaction_date.ToString()); } }
2016年8月1日のテストの全リスト:
C#
-
ShouldAddCustomer
-
ShouldDeleteCustomer
-
ShouldDeposit
-
ShouldEvaluateTransactionDetails
-
ShouldListTransactions
-
ShouldLoginCustomer
-
ShouldOpenAccount
-
ShouldSortCustomersAccounts
-
ShouldWithdraw
Java(デスクトップ)
-
testAddCustomer
-
testCustomerLogin
-
testDepositAndWithdraw
-
testEvaluateTransactionDetails
-
testListTransactions
-
testOpenAccount
-
testSortCustomerAccounts
Java(CI /トラビス)
-
testAddition
-
testChangeSelectedtOption
-
testEvaluate
-
testFindElementByOptions
-
testFindElementByRepeaterColumn
-
testFindElementByRepeaterWithBeginEnd
-
testFindSelectedtOption
CIテスト-単純化され、テストされたページがディスクから直接ロードされます。
String localFile = "bind_select_option_data_from_array_example.htm"; URI uri = NgByIntegrationTest.class.getClassLoader()。GetResource(localFile).toURI(); ngDriver.navigate()。to(uri.toString()));
単純化されたシナリオを実行する
Iterator <WebElement> options = ngDriver.findElements(NgBy.repeater( "option in options"))。Iterator(); while(options.hasNext()){ WebElementオプション=(WebElement)options.next(); if(option.getText()。isEmpty()){ 休憩; } if(option.getText()。equalsIgnoreCase( "two")){ option.click(); } } NgWebElement要素= ngDriver.findElement(NgBy.selectedOption( "myChoice")); assertThat(element.getText()、containsString( "two"));
phantomJS
ドライバーが
phantomJS
Code Projectに関する記事(より詳細なバージョン)も公開されており、最新のプロジェクトアーカイブが定期的にダウンロードされています。 githubの両方のプロジェクト:
-完全に機能し、ほぼ毎日コミットします。