Scalatestを使用した情報システムの監視と統合テストの実装。 パート2





前の記事Scalatestを使用した情報システムの監視と統合テストの実装で、Ideaでのプロジェクトの作成と簡単なテストの作成について説明しました。 このパートでは、フレームワークのいくつかの機能と、テストの作成中に発生する問題を解決するためのテクニックを検討します。

テストの実行の詳細について詳しく説明し、レポートの詳細、Seleniumを使用する機能を分析し、タイムアウト、期待、オペレーティングシステムコマンドの呼び出し、テストを含むjarファイルの生成にも注意を払います。



実行中のテストの機能


別のクラスを実行するには、Ideaから実行するか、コンソールでクラスを使用してtestOnlyコマンドを実行します。

sbt "testOnly org.example.MyTest1 org.example.MyTest2"
      
      





たとえば、記号*を使用できます。

 sbt "testOnly *MyTest*"
      
      





「MyTest」という名前を含むすべてのテストを実行します

デフォルトでは、すべてのクラスは並行して実行されます。 build.sbtでオプションを使用できます

 parallelExecution in Test := false
      
      





これにより、実行の一貫性が保たれます。

詳細については、 www.scala-sbt.org / 0.13 / docs / Testing.htmlをご覧ください。



レポートファイルの作成


テストに合格した後にレポートを生成するには、テストを実行するための引数を追加する必要があります。 引数はscalatest.org/user_guide/using_the_runnerにあります。 それらのすべてがsbtから実行できるわけではないので、実験する必要があります。

ライブラリーscalatest% "test-> *"のパラメーターbuild.sbtで補足します。

 libraryDependencies += "org.scalatest" % "scalatest_2.11" % "2.2.6" % "test->*"
      
      





パラメーターを含む行を追加します

 (testOptionsinTest) += Tests.Argument(TestFrameworks.ScalaTest, "-hD", "report", "-fW", "report.txt")
      
      





この場合、テストを開始すると、「report」フォルダー内の実行時間(「D」)を示すhtml(「-h」)レポートと、色(「W」を指定せずにテキストレポートファイル(「f」) 、ファイル内のANSIカラーコードはLinuxシステムでは正しく表示されますが、Windowsでは松葉杖が必要です)

レポートをUTF8エンコードで生成するには、Windowsのロシア語の文字に問題はありません。sbt\ conf \ sbtconfig.txtにオプションを追加することをお勧めします

 -Dfile.encoding=UTF8
      
      







レポートフォルダーには、index.htmlファイルと、各クラスに1つずつの複数の.htmlファイルが含まれます。 理論的には、クラス名にロシア語の文字を使用できますが、ファイル<RussianTestClassName> .htmlを開くときに問題が発生する場合があります。

スクリーンショットを保存してレポートに貼り付けるメソッドを追加して、GetTestクラスを少し変更しましょう。

 import org.openqa.selenium.WebDriver import org.openqa.selenium.firefox.FirefoxDriver import org.scalatest.selenium.WebBrowser import org.scalatest.{Matchers, FreeSpec} import scala.io.Source class GetTest extends FreeSpec with Matchers with WebBrowser{ val pageURL = "http://scalatest.org/about" def get(url: String) = Source.fromURL(url, "UTF-8").mkString implicit val webDriver: WebDriver = new FirefoxDriver() //      setCaptureDir("report") "Get   " + pageURL + "   " in { get(pageURL) should include("<title>ScalaTest</title>") } "  %s   ".format(pageURL) in { go to pageURL pageTitle should be ("ScalaTest") //   capture to ("MyScreenShot.png") //    markup("<a href=\"http://scalatest.org/about\"> </a>") markup("<img src='MyScreenShot.png' /> ") } " " in { quit() } }
      
      





コンソールで実行します

 sbt "testOnly GetTest"
      
      





テストに合格すると、プロジェクトレポートのルートに「report.txt」ファイルが生成され、HTMLレポートのファイルを含む「レポート」フォルダーが生成されます。







スクリプトのステップの結果はコンソールに表示されず、結果のみが表示されることを明確にする必要があります。

レポートを開くと、ページのスクリーンショットが表示されます







この例およびSeleniumのその他の例では、ブラウザーを閉じることは別のステップになります

  " " in { quit() }
      
      





ステップは最後に完了する必要があります。 クラス本体にcloseコマンドを記述すると、ステップの開始前に実行され、エラーが発生します。 少し後、すべてのステップを完了した後、コマンドの実行方法を検討します。



期待


検証オブジェクトがないためにテストがクラッシュする状況があります...たとえば、データベースのレコードは、イベントまたはWebページの要素がすぐに表示されない数秒後に表示されますが、クライアントでスクリプトが処理された後です。

この場合、一時停止を使用できます(たとえば、Thread.sleep(1000)コマンドはコードの実行を1秒間一時停止します)が、最終的には使用することをお勧めします。

最終的に-通過が成功するかタイムアウトになるまで、定期的に操作のブロックを実行できます。

例を考えてみましょう:

 class OpenScalatest extends FreeSpec with WebBrowser{ implicit val webDriver: WebDriver = new FirefoxDriver() val pageURL = "https://www.google.ru/" "  ScalaTest" in { go to pageURL textField("q").value = "ScalaTest" clickOn("btnG") } "  'ScalaTest'" in { click on partialLinkText("ScalaTest") } " " in { quit() } }
      
      





この例では、GoogleでScalaTestページを検索し、そのページに移動します。

テストは、「WebElement 'ScalaTest' not found。」というエラーで失敗します。



問題は、すべてのリソースがロードされた後、ドライバーがページをロードしたと見なすことです。 ただし、ページが読み込まれた後にクライアント上で要素を形成できるという事実は考慮されていません。

最終的にブロック内のリンクをクリックするステップをラップします。 これを行うには、特性をクラス定義に混ぜます

「やがて」

時間を操作するためのコンポーネントのインポート

 Import org.scalatest.time.SpanSugar._
      
      





最終的に再定義

 implicit override val patienceConfig = PatienceConfig(timeout = (2 seconds), interval = (250 millis))
      
      





そして、待機ステップを終了します

 eventually{clickonpartialLinkText("ScalaTest")}
      
      





結果として、

 class OpenScalatest extends FreeSpec with WebBrowser with Eventually{ implicit val webDriver: WebDriver = new FirefoxDriver() val pageURL = "https://www.google.ru/" implicit override val patienceConfig = PatienceConfig(timeout = (2 seconds), interval = (250 millis)) "  ScalaTest" in { go to pageURL textField("q").value = "ScalaTest" clickOn("btnG") } "  'ScalaTest'" in { eventually{click on partialLinkText("ScalaTest")} } " " in { quit() } }
      
      





このため、準備を確認するためにリソースの定期的な調査であるポーリングを実装します。

現在、250ミリ秒ごとに要素の可用性がチェックされ、2秒以内に表示されない場合、テストは失敗します。

詳細: doc.scalatest.org/2.2.6/index.html#org.scalatest.concurrent.Eventually



コードのブロックが非常に長い時間実行できる場合があり、実行時間を制限する必要があります。 failAfterコマンドとcancelAfterコマンドを含むTimeoutsトレイトを使用します。

たとえば、ページが5秒以上読み込まれた場合、エラーが発生したと考えられます。

 class DevianArt extends FreeSpec with WebBrowser with Timeouts { implicit val webDriver: WebDriver = new FirefoxDriver() val pageURL = "http://www.deviantart.com/" "  %sc   ".format(pageURL) in { failAfter(5 seconds){ go to (pageURL)} } " " in { quit() } }
      
      





ページの詳細

doc.scalatest.org/2.2.6/index.html#org.scalatest.concurrent.Timeouts

したがって、応答の待機時間を制限することができます。



テストステップの前後にアクションを実行する


場合によっては、テストステップを完了する前、テストステップを完了した後、各ステップの前後に特定のアクションを実行する必要があります。

これを行うには、BeforeAndAfterAllおよびBeforeAndAfter特性を使用します。

テストの各ステップの後にスクリーンショットが撮られ、すべてのステップの後にブラウザーが閉じられる例を考えてみましょう

 class CreateScalatestCaptures extends FreeSpec with WebBrowser with BeforeAndAfter with BeforeAndAfterAll{ implicit val webDriver: WebDriver = new FirefoxDriver() val pageURL = "http://www.scalatest.org/" setCaptureDir("report") //      TimeStamp      def createScreenCaptureToReport(fileName: String = System.currentTimeMillis + ".png"): Unit = { captureTo(fileName) markup("<img src='" + fileName + "' width='50%' /> ") } "  %s".format(pageURL) in { go to pageURL } "  'Quick Start'" in { click on partialLinkText("Quick Start") } //      after{ createScreenCaptureToReport() } //     override def afterAll(){ quit() } }
      
      







セレンに関する小さな追加


scalatestにはSeleniumDSLが含まれており、その適用例は上記で説明しました。 ページで

scalatest.org/user_guide/using_selenium

かなり良い説明が含まれていますが、さらに発言できる点がいくつかあります。

場合によっては、ブラウザウィンドウのサイズを制御する必要があります。 これは、インターフェースを使用して行われます。

 webDriver.manage().window()
      
      





例えば

 webDriver.manage().window().maximize()
      
      





ウィンドウを最大化する(デフォルトでは、ブラウザはウィンドウモードでディゾルブします)、または

 val browserDimension = new org.openqa.selenium.Dimension(1920,2160) webDriver.manage().window().setSize(browserDimension)
      
      





サイズ1920 * 2160のウィンドウを形成します



ウィンドウを切り替えるには、コードを使用します

 val arr = windowHandles.toArray switch to window(arr(1))
      
      





コンソールで実行した後、2つのスクリーンショットを含む美しいレポートを取得します。

一意の名前を持つ画像を生成すると、各開始時にファイルが生成されることに注意してください。 これを検討する価値があり、ファイルを使用してディレクトリを定期的にクリーンアップします。



ブラウザコンソールでエラーを追跡することもできます。

インポートする必要があります

 import org.openqa.selenium.logging.{LogType, LoggingPreferences} import org.openqa.selenium.remote.{CapabilityType, DesiredCapabilities}
      
      





ブラウザを宣言する場所に、次の行を追加します

 var logPref: LoggingPreferences = new LoggingPreferences() logPref.enable(LogType.BROWSER, Level.SEVERE)//   "SEVERE" val capability = DesiredCapabilities.firefox() capability.setCapability(CapabilityType.LOGGING_PREFS, logPref) implicit val webDriver: WebDriver = new FirefoxDriver(capability)//      
      
      





ステップコードでは、レポートにログを表示するために記述します

 val browserLogs = webDriver.manage().logs().get(LogType.BROWSER).getAll.toArray browserLogs.foreach(x=> markup("<q>%s</q>".format(x)))
      
      





ログにエラーがあるときにステップを失敗させる場合-追加

 browserLogs.size should be (0)
      
      





OSコマンドの実行


テストを実行するOSコマンドを実行する必要がある場合があります。

次の例は、空きディスク領域の量を確認する方法と、pingコマンドでホストの可用性を確認する方法を示しています。

このために、別個のCMDUtilsオブジェクトが作成され、OSが決定され、コマンドが



 import scala.math._ import scala.sys.process._ object CMDUtils extends Exception{ val os = System.getProperty("os.name").substring(0,3) def freeSpace: Long = { var cmd: Seq[String] = null // ,       os match { case "Win" => cmd = Seq("powershell", "-command ", "(fsutil volume diskfree c:).split(' ')[-1]") case "Lin" => cmd = Seq("/bin/sh", "-c", "df / -B1 | sed -n 2p | awk '{print $4}'") case _ => throw new Exception("  ") } //        val output = cmd.!! //           output.trim.toLong/pow(1024,3).toLong } def pingHost(host: String): Boolean = { var cmd: Seq[String] = null os match { case "Win" => cmd = Seq("powershell", "-command ", "ping %s | Out-Null ; echo $?".format(host)) case "Lin" => cmd = Seq("/bin/sh", "-c", "ping %s -c 4 &> /dev/null; if (($?==0)); then echo true; else echo false; fi".format(host)) case _ => throw new Exception("  ") } //     true/false cmd.!!.trim.toBoolean } }
      
      







次に、オブジェクトのメソッドがテストから呼び出されます

 class CMDExecute extends FreeSpec with Matchers{ val limit: Long = 10 //    "    %s   ".format(limit) in { CMDUtils.freeSpace should be > limit } var host1 = "8.8.8.194" "   %s".format(host1) in { CMDUtils.pingHost(host1) should be(true) } var host2 = "8.8.8.8" "   %s".format(host2) in { //     "true" assert(CMDUtils.pingHost(host2)) } }
      
      





OSコマンドを使用してzabbix_senderユーティリティを使用して、テスト結果をzabbixサーバーに送信することもできます

複雑な操作(データベースのクエリ、キューマネージャーからのメッセージの送受信、XMLの解析または生成)を実行するには、テストでメソッドが呼び出される別のオブジェクトまたはクラスを作成します。



実行可能jarファイルの作成


場合によっては、プロジェクトからではなく、すべての依存関係を含む別個のjarファイルとしてテストを実行するのが理にかなっています。 sbt testコマンドを実行するたびに、プロジェクトファイルがコンパイルされます。 変更がなかった場合、これを確認するには時間がかかります。 ビルドjarを使用すると、テストの各実行のコンパイル/アセンブルに時間を費やすことなく、jarの形成を実行し、コンパイルなしで毎回テストを実行できます。 ファイルに含まれる依存関係により、Javaが存在する任意のマシンでテストを実行できます。

デフォルトでは、テストはjarファイルに含まれていないため、テストクラスがメインコードから実行されるようにする必要があります。

これを行うには、ライブラリのスコープを変更し、「test-> *」の表示を削除します

 libraryDependencies += "org.scalatest" %% "scalatest_2.11" % "2.2.6"
      
      





明示的な指示がない場合、これは「コンパイル」構成です。

詳細については、 maven.apache.org / guides / introduction / introduction-to-dependency-mechanism.htmlをご覧ください。

依存関係を追加する必要がありますが、それなしではHTMLレポートを作成できません

  libraryDependencies += "org.pegdown" % "pegdown" % "1.6.0"
      
      





次に、テストクラスのファイルをsrc / test / scalaフォルダーからsrc / main / scalaフォルダーに移動する必要があります

その後、オブジェクトを作成し、MainAppという名前でテストを実行します。

 import org.scalatest.tools.Runner object MainApp extends App{ Runner.run(Array("-s", "TestClass", "-h", "report")) }
      
      





クラスは、パラメータが渡されるRunnerオブジェクトのrunメソッドを開始します

-sは、実行するテストクラスの名前です。

-h-htmlレポートのフォルダー



他のオプションについては、 http: //www.scalatest.org/user_guide/using_the_runnerを参照してください。



その後、sbt runを実行します。クラスからのテストはパスし、レポートを含むフォルダーとレポートを含むファイルを作成する必要があります。

runコマンドでテストを実行した後、依存関係を使用してjarファイルをコンパイルできます。

これを行うには、プラグインgithub.com/sbt/sbt-assemblyを追加します



ファイルproject / plugins.sbtに次の行を追加します

 addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.1")
      
      





コマンド実行時にプロジェクトを更新した後

 sbt assembly
      
      





jarファイルがtarget / scala-2.11ディレクトリに生成されます

java -jar .jarコマンドを使用して実行すると、テストの実行とレポートの生成が得られます。



build.sbtで指定することにより、プロジェクトルートにファイルを作成することができます。

 assemblyOutputPath in assembly := baseDirectory.value / "tests.jar"
      
      





このアプローチの適用は、アセンブリが頻繁に起動するがめったに変更されない場合、またはアセンブリの依存関係がかなりの時間ダウンロードされるか、インターネットが存在しない別のマシンでテストをすばやく実行する必要がある場合に受け入れられます。 マイナスのうち、大きなファイルサイズに注意することができます。 (たとえば、Firefoxドライバーを使用したテストの場合は40 mb)、jarファイルをビルドするための時間。



テストが失敗したときに特別な終了コードが必要な場合(たとえば、アセンブリがCIサーバーに該当する場合)、ランナーから返された値を確認してコードをインストールする必要があります。

 object MainApp extends App{ val res = Runner.run(Array("-s", "TestClass", "-h", "report")) if (!res) sys.exit(1) }
      
      







また、テストにはコードを再利用する機能があります。 たとえば、ブラウザインスタンスを作成し、テストに合格した後に開くと、サイトでの承認は、テストクラスが継承される別の特性に分離できます。

構成には、typesafe( https://github.com/typesafehub/config )の構成コンポーネントを使用できます



したがって、ライブラリを操作する基本的な方法が考慮されたため、便利で汎用的な自動テストを作成できます。

外には、フィクスチャ、モックオブジェクト、プロパティベースのテスト、テーブル駆動テスト、Sikuliの使用、UIテストを自動化するjavaロボット、その他多くのおいしいものがありました。

このフレームワークの主な利点の1つは、高品質のドキュメントとサンプルが利用できることです。 これにより、フレームワークの学習と使用が楽しく効果的になります。

この技術スタックの利点は、当社での成功した使用経験によって確認されています。



All Articles