はじめに
こんにちは! SeleniumおよびC#でのWebアプリケーションの自動テストに関する記事の第2部を紹介します。 そして、最初の部分が読者の間で怒りを引き起こした「キャプテン証拠」のカテゴリーからのものであった場合、この部分には多くのコードがあります。 それで、なぜSelenium APIのラッパーを書くのですか? 私の意見では、ユーザーには次の問題が発生する可能性があります。
- IWebDriverインターフェースは、ブラウザー管理の面でかなり貧弱な機能を提供します。 したがって、必要なものはすべて自分で書く必要があります
- 要素の説明は、その検索と同時に発生します。 要素が定義された時点で、ブラウザに存在している必要があります。 非常に多くの場合、各要素のゲッターを書くことで解決します。 やりすぎでパフォーマンスの面で悪い
- ISearchContext.FindElementsは、OpenQA.Selenium.By型のパラメーターを1つだけ受け入れます。 一度に複数のプロパティで検索することはできません。 通常、要素は最初の基準で検索され、その後、スクリーニングは残りから始まります
- 一見明らかな多くのメソッドとプロパティの欠如。 例:Exist、SetText、Select、SetCheck、InnerHtmlなど。 代わりに、Click、SendKeys、およびTextを使用したコンテンツにする必要があります。
- FirefoxやChromeなど、さまざまなブラウザーでの多くの問題、要素はクリックしますが、IEでは-いいえ。 特別な場合、「クランチ」を作成する必要があります
- パフォーマンス。 はい、ドライバーは高速で動作しません。 IEはいつものように残りの部分を先取りしています-検索には数秒、場合によっては数十秒かかることがあります
さて、多くの問題-多くの解決策。 この部分ではすべてを一度に述べることはできませんし、できません。 長い投稿は面白くなく、それを書いているときでも、熱意は急激に低下します)したがって、このパートは2.1です。
参照資料
パート1:はじめに
パート2.1:Selenium APIラッパー-ブラウザー
パート2.2:Selenium APIラッパー-WebElement
パート3:WebPages-ページの説明
パート4:最後にテストを書く
フレームワークの公開
行こう ブラウザーでのラッパーの実装:ブラウザークラス
上記のコードがあなたにとって複雑に見えないことを本当に願っています。
この例では、すべてのIWebDriver固有のコードがカプセル化されており、co病者は外側にはみ出しません。 自動テスト開発者は、ドライバーに直接アクセスできません。 その結果、同じ名前のドライバーメソッドが呼び出されるメソッドがあります。
コードにはコメントがありません。これは良い口調です。ある賢い人が言ったように、「コードのコメントはスープの髪の毛のようなものです。 髪のスープを食べますか?!」
私はMicrosoft Code Contractsを使用していますが、電話を恐れる必要はありません。
テストされた製品でjqueryが接続されており、それを使用していくつかのアクションが実行されることにも注意する価値があります。
Browserクラスは3つのブラウザーをサポートします。
- Firefox
- クロム
- インターネットエクスプローラー
残念ながら、Opera用のC#ドライバーはまだありません:(
次のような標準のメソッドとプロパティのセットが実装されています。
- 開始する
- やめる
- ナビ
- ナビゲートバック
- リフレッシュ
- WaitReadyState
- 要素を見つける
- SelectedBrowser
- URL
- 役職
- PageSource
- その他
名前はかなり明白だと思うので、先に進みましょう。
特定の機能も実装しました:
- WaitAjax
- SwitchToFrame
- SwitchToPopupWindow
- AcceptAlert
- GetScreenshot + SaveScreenshot
- Resizewindow
- ExecuteJavaScript
- ドラッグアンドドロップ
- その他
namespace Autotests.Utilities { [Serializable] public enum Browsers { [Description("Windows Internet Explorer")] InternetExplorer, [Description("Mozilla Firefox")] Firefox, [Description("Google Chrome")] Chrome } public static class Browser { #region Public properties public static Browsers SelectedBrowser { get { return Settings.Default.Browser; } } public static Uri Url { get { WaitAjax(); return new Uri(WebDriver.Url); } } public static string Title { get { WaitAjax(); return string.Format("{0} - {1}", WebDriver.Title, EnumHelper.GetEnumDescription(SelectedBrowser)); } } public static string PageSource { get { WaitAjax(); return WebDriver.PageSource; } } #endregion #region Public methods public static void Start() { _webDriver = StartWebDriver(); } public static void Navigate(Uri url) { Contract.Requires(url != null); WebDriver.Navigate().GoToUrl(url); } public static void Quit() { if (_webDriver == null) return; _webDriver.Quit(); _webDriver = null; } public static void WaitReadyState() { Contract.Assume(WebDriver != null); var ready = new Func<bool>(() => (bool)ExecuteJavaScript("return document.readyState == 'complete'")); Contract.Assert(Executor.SpinWait(ready, TimeSpan.FromSeconds(60), TimeSpan.FromMilliseconds(100))); } public static void WaitAjax() { Contract.Assume(WebDriver != null); var ready = new Func<bool>(() => (bool)ExecuteJavaScript("return (typeof($) === 'undefined') ? true : !$.active;")); Contract.Assert(Executor.SpinWait(ready, TimeSpan.FromSeconds(60), TimeSpan.FromMilliseconds(100))); } public static void SwitchToFrame(IWebElement inlineFrame) { WebDriver.SwitchTo().Frame(inlineFrame); } public static void SwitchToPopupWindow() { foreach (var handle in WebDriver.WindowHandles.Where(handle => handle != _mainWindowHandler)) // TODO: { WebDriver.SwitchTo().Window(handle); } } public static void SwitchToMainWindow() { WebDriver.SwitchTo().Window(_mainWindowHandler); } public static void SwitchToDefaultContent() { WebDriver.SwitchTo().DefaultContent(); } public static void AcceptAlert() { var accept = Executor.MakeTry(() => WebDriver.SwitchTo().Alert().Accept()); Executor.SpinWait(accept, TimeSpan.FromSeconds(5)); } public static IEnumerable<IWebElement> FindElements(By selector) { Contract.Assume(WebDriver != null); return WebDriver.FindElements(selector); } public static Screenshot GetScreenshot() { WaitReadyState(); return ((ITakesScreenshot)WebDriver).GetScreenshot(); } public static void SaveScreenshot(string path) { Contract.Requires(!string.IsNullOrEmpty(path)); GetScreenshot().SaveAsFile(path, ImageFormat.Jpeg); } public static void DragAndDrop(IWebElement source, IWebElement destination) { (new Actions(WebDriver)).DragAndDrop(source, destination).Build().Perform(); } public static void ResizeWindow(int width, int height) { ExecuteJavaScript(string.Format("window.resizeTo({0}, {1});", width, height)); } public static void NavigateBack() { WebDriver.Navigate().Back(); } public static void Refresh() { WebDriver.Navigate().Refresh(); } public static object ExecuteJavaScript(string javaScript, params object[] args) { var javaScriptExecutor = (IJavaScriptExecutor)WebDriver; return javaScriptExecutor.ExecuteScript(javaScript, args); } public static void KeyDown(string key) { new Actions(WebDriver).KeyDown(key); } public static void KeyUp(string key) { new Actions(WebDriver).KeyUp(key); } public static void AlertAccept() { Thread.Sleep(2000); WebDriver.SwitchTo().Alert().Accept(); WebDriver.SwitchTo().DefaultContent(); } #endregion #region Private private static IWebDriver _webDriver; private static string _mainWindowHandler; private static IWebDriver WebDriver { get { return _webDriver ?? StartWebDriver(); } } private static IWebDriver StartWebDriver() { Contract.Ensures(Contract.Result<IWebDriver>() != null); if (_webDriver != null) return _webDriver; switch (SelectedBrowser) { case Browsers.InternetExplorer: _webDriver = StartInternetExplorer(); break; case Browsers.Firefox: _webDriver = StartFirefox(); break; case Browsers.Chrome: _webDriver = StartChrome(); break; default: throw new Exception(string.Format("Unknown browser selected: {0}.", SelectedBrowser)); } _webDriver.Manage().Window.Maximize(); _mainWindowHandler = _webDriver.CurrentWindowHandle; return WebDriver; } private static InternetExplorerDriver StartInternetExplorer() { var internetExplorerOptions = new InternetExplorerOptions { IntroduceInstabilityByIgnoringProtectedModeSettings = true, InitialBrowserUrl = "about:blank", EnableNativeEvents = true }; return new InternetExplorerDriver(Directory.GetCurrentDirectory(), internetExplorerOptions); } private static FirefoxDriver StartFirefox() { var firefoxProfile = new FirefoxProfile { AcceptUntrustedCertificates = true, EnableNativeEvents = true }; return new FirefoxDriver(firefoxProfile); } private static ChromeDriver StartChrome() { var chromeOptions = new ChromeOptions(); var defaultDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\..\Local\Google\Chrome\User Data\Default"; if (Directory.Exists(defaultDataFolder)) { Executor.Try(() => DirectoryExtension.ForceDelete(defaultDataFolder)); } return new ChromeDriver(Directory.GetCurrentDirectory(), chromeOptions); } #endregion } }
Settings.Default.Browserはプロジェクトプロパティで設定されるパラメーターであり、Executor.SpinWaitは条件がタイムアウトになるのを待ってtrue / falseを返すヘルパーの一種であることにコメントする価値があります。 魔法の文字列もあります、ごめんなさい)