20211124のC#に関する記事は6件です。

WinAppDriverを使ってUITestする(未完)

こんばんは。 Azure DevOpsでUITestをやっているのですが、詰まってしまってどうしようもないので、ひとまずアウトプットしようと思って記事を書いています。 概要 Visual Studio EnterpriseでなくてもUITestができると聞いたので、boiler's GraphicsにUITestを導入してみました。C#テストプロジェクトでUITestを実現するにはWinAppDriverというソフトウェアをインストールする必要があるとのことなのです。 WinAppDriver のインストール 今回はWinAppDriverのReleaseページのv1.3 Release Candidate 1 (1.2.99)を選択しました。 インストーラーはWindowsApplicationDriver-1.2.99-win-x64.exeです。 WinAppDriverの実行 WinAppDriverをインストールしたら、C:\Program Files\Windows Application Driver\WinAppDriver.exeをダブルクリックして起動します。 ↑この状態になったら放置します。 テストプロジェクトに(NuGetで)ライブラリをインストールする またC#テストプロジェクトにNuGetパッケージマネージャーで、"Microsoft.WinAppDriver.Appium.WebDriver"のバージョン1.0.1-Previewをインストールします。プレビュー版なので、☑プレリリースを含めるにチェックを入れて下さい。 UITestを書く そして、C#テストプロジェクトにUITestを書きますが、手始めにAppSession.csというUITest共通の基本クラスを作成します。ここでsessionなどを準備します。 UITest/AppSession.cs using NUnit.Framework; using OpenQA.Selenium.Appium.Windows; using OpenQA.Selenium.Remote; using System; using System.IO; using System.Reflection; namespace boilersGraphics.Test.UITests { public class AppSession { // Note: append /wd/hub to the URL if you're directing the test at Appium private const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723"; private static readonly string AppPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "boilersGraphics.exe");//"Microsoft.WindowsCalculator_8wekyb3d8bbwe!App"; protected static WindowsDriver<WindowsElement> session; [SetUp] public static void Setup() { // Launch Calculator application if it is not yet launched if (session == null) { // Create a new session to bring up an instance of the Calculator application // Note: Multiple calculator windows (instances) share the same process Id DesiredCapabilities appCapabilities = new DesiredCapabilities(); appCapabilities.SetCapability("app", AppPath); appCapabilities.SetCapability("deviceName", "WindowsPC"); session = new WindowsDriver<WindowsElement>(new Uri(WindowsApplicationDriverUrl), appCapabilities); Assert.That(session, Is.Not.Null); // Set implicit timeout to 1.5 seconds to make element search to retry every 500 ms for at most three times session.Manage().Timeouts().ImplicitWait = TimeSpan.FromMinutes(1); session.Manage().Window.Maximize(); } } [TearDown] public static void TearDown() { // Close the application and delete the session if (session != null) { session.Quit(); session = null; } } } } ※テスト安定化を図るために、WindowsDriverSessionでMaximize()して、テスト対象アプリのウィンドウを最大化しています。これをすることで、テスト対象アプリのウィンドウが最も手前に来てテストが安定します。 あとは、思う存分にUITestのコードを書くだけです。今回は(1)チェッカーパターンの出来損ないが収録されているxmlファイルを読み込んで、jpgファイルにエクスポートするのと、(2)単なる白背景のキャンパスをそのままjpgファイルにエクスポートする2つを実装してみます...。 下記ではライブラリとして、ログ出力のためにNLog等を使用しています。(なくてもおk!) UITests/ExportTest.cs using NLog; using NUnit.Framework; using OpenQA.Selenium; using System.IO; using System.Reflection; using System.Threading; namespace boilersGraphics.Test.UITests { [TestFixture] public class ExportTest : AppSession { [Test] public void 真っ白なキャンパスをエクスポートする() { var dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var exportFilePath = $"{dir}\\ExportTest.jpg"; try { session.FindElementByAccessibilityId("Export").Click(); session.FindElementByAccessibilityId("ExportFileName").SendKeys(exportFilePath); session.FindElementByAccessibilityId("PerformExport").Click(); Thread.Sleep(1000); LogManager.GetCurrentClassLogger().Info(exportFilePath); Assert.That(File.Exists(exportFilePath), Is.EqualTo(true)); } finally { File.Delete(exportFilePath); } } [Test] public void チェッカーパターンを読み込んでエクスポートする() { LogManager.GetCurrentClassLogger().Info("A"); var dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var loadFilePath = $"{dir}\\XmlFiles\\checker_pattern.xml"; var exportFilePath = $"{dir}\\ExportTest2.jpg"; try { LogManager.GetCurrentClassLogger().Info("B"); session.FindElementByAccessibilityId("Load").Click(); LogManager.GetCurrentClassLogger().Info("C"); session.FindElementByAccessibilityId("1").Click(); LogManager.GetCurrentClassLogger().Info("D"); session.Keyboard.SendKeys(Keys.Alt + "N" + Keys.Alt); LogManager.GetCurrentClassLogger().Info("E"); session.Keyboard.SendKeys(Keys.Alt + "N" + Keys.Alt); LogManager.GetCurrentClassLogger().Info("F"); session.FindElementByAccessibilityId("1148").SendKeys(loadFilePath); LogManager.GetCurrentClassLogger().Info("G"); session.FindElementByAccessibilityId("1").Click(); LogManager.GetCurrentClassLogger().Info("H"); Thread.Sleep(1000); session.FindElementByAccessibilityId("Export").Click(); LogManager.GetCurrentClassLogger().Info("I"); Thread.Sleep(1000); session.FindElementByAccessibilityId("ExportFileName").SendKeys(exportFilePath); LogManager.GetCurrentClassLogger().Info("J"); session.FindElementByAccessibilityId("PerformExport").Click(); LogManager.GetCurrentClassLogger().Info("K"); Thread.Sleep(1000); LogManager.GetCurrentClassLogger().Info("L"); Assert.That(File.Exists(exportFilePath), Is.EqualTo(true)); LogManager.GetCurrentClassLogger().Info("M"); } finally { LogManager.GetCurrentClassLogger().Info("N"); File.Delete(exportFilePath); LogManager.GetCurrentClassLogger().Info("O"); } } } } ローカル環境でテスト実行 あと注意点なのですが、Windowsの設定で英語キーボードじゃないと"\"が文字化けして"]"になってしまう問題があります。これは、テストを実行する前にWindowsキー+Spaceキーでキーボードレイアウトを英語(米国)にする必要があります。この辺将来のアップデートで日本語キーボードも使えるようにして欲しぃ...。 テストを書いたら、ローカルでテストしてみます。ローカルではテストはすんなり通ると思います。 ↑ちょっと画面端が切れてますがご了承下さい。ScreenToGifだとフルスクリーンで録画できないんです...。 でも、こうして自動でUITestが動いていることがわかると思います。 Azure DevOps(CIサーバー)でテスト実行 さて、出来上がったUITestはローカル環境で検証しましたが、これをクラウドのCI環境で自動で検証させたいという要望が上がってきました。試しにAzure DevOpsでUITestを実行させてみましょう。 アドオンインストール Azure DevOpsでWinAppDriverを実行するにはアドオンをインストールする必要があります。 azure-pipelines.ymlに追記 次に、azure-pipelines.ymlにWinAppDriverの起動タスクと終了タスクを追記する必要があります。 azure-pipelines_develop.yml # .NET Desktop # Build and run tests for .NET Desktop or Windows classic desktop solutions. # Add steps that publish symbols, save build artifacts, and more: # https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net trigger: - develop pool: vmImage: 'windows-latest' variables: solution: '**/*.sln' buildPlatform: 'Any CPU' buildConfiguration: 'Release' disable.coverage.autogenerate: 'true' steps: - task: NuGetToolInstaller@1 - task: NuGetCommand@2 inputs: restoreSolution: '$(solution)' - task: VSBuild@1 inputs: solution: '$(solution)' platform: '$(buildPlatform)' configuration: '$(buildConfiguration)' - task: Windows Application Driver@0 inputs: OperationType: 'Start' AgentResolution: '1080p' - task: CmdLine@2 displayName: "NUnit & OpenCover" inputs: script: > packages\OpenCover.4.7.1221\tools\OpenCover.Console.exe -register:Path64 -target:"packages\NUnit.ConsoleRunner.3.12.0\tools\nunit3-console.exe" -targetargs:"boilersGraphics.Test.dll" -targetdir:"boilersGraphics.Test\bin\$(buildConfiguration)" -returntargetcode -output:"coverage.xml" -filter:"+[boilersGraphics]* +[TsOperationHistory]* -[*]XamlGeneratedNamespace*" - task: Windows Application Driver@0 condition: always() inputs: OperationType: 'Stop' - task: PublishTestResults@2 displayName: "Publish unit test result" condition: always() inputs: testResultsFormat: 'NUnit' testResultsFiles: '**/TestResult.xml' failTaskOnFailedTests: false - task: reportgenerator@4 condition: always() inputs: reports: '**\coverage.xml' targetdir: 'coveragereport' - task: PublishCodeCoverageResults@1 condition: always() inputs: codeCoverageTool: 'Cobertura' summaryFileLocation: 'coveragereport\Cobertura.xml' reportDirectory: 'coveragereport\' # Archive files # Compress files into .7z, .tar.gz, or .zip - task: ArchiveFiles@2 condition: always() inputs: rootFolderOrFile: '$(System.DefaultWorkingDirectory)\boilersGraphics\bin\Release' includeRootFolder: false archiveType: 'zip' # Options: zip, 7z, tar, wim tarCompression: 'gz' # Optional. Options: gz, bz2, xz, none archiveFile: '$(Build.ArtifactStagingDirectory)/boilersGraphics_$(Build.BuildId).zip' replaceExistingArchive: true #verbose: # Optional #quiet: # Optional # GitHub Release # Create, edit, or delete a GitHub release - task: GitHubRelease@0 condition: always() inputs: gitHubConnection: dhq-boiler-azure-devops repositoryName: '$(Build.Repository.Name)' action: 'create' # Options: create, edit, delete target: '$(Build.SourceVersion)' # Required when action == Create || Action == Edit tagSource: manual # Required when action == Create# Options: auto, manual #tagPattern: # Optional tag: unstable-$(Build.BuildNumber) # Required when action == Edit || Action == Delete || TagSource == Manual #title: # Optional #releaseNotesSource: 'file' # Optional. Options: file, input #releaseNotesFile: # Optional #releaseNotes: # Optional assets: '$(Build.ArtifactStagingDirectory)\boilersGraphics_$(Build.BuildId).zip' assetUploadMode: 'delete' # Optional. Options: delete, replace isDraft: false # Optional isPreRelease: true # Optional addChangeLog: true # Optional compareWith: 'lastFullRelease' # Required when addChangeLog == True. Options: lastFullRelease, lastRelease, lastReleaseByTag #releaseTag: # Required when compareWith == LastReleaseByTag - task: CmdLine@2 displayName: "pip install python-oauth2" inputs: script: > pip install twitter # Python script # Run a Python file or inline script - task: PythonScript@0 inputs: scriptSource: 'inline' # Options: filePath, inline #scriptPath: azure_devops/python_script/tweet.py # Required when scriptSource == filePath script: > from twitter import Twitter, OAuth access_token = '$(AccessToken)' access_token_secret = '$(AccessTokenSecret)' api_key = '$(APIKey)' api_secret = '$(APIKeySecret)' t = Twitter(auth = OAuth(access_token, access_token_secret, api_key, api_secret)) text = 'https://github.com/dhq-boiler/boiler-s-Graphics/releases/tag/unstable-$(Build.BuildNumber)' statusUpdate = t.statuses.update(status=text) #arguments: # Optional #pythonInterpreter: # Optional #workingDirectory: # Optional #failOnStderr: false # Optional ここで重要なのはTestを実行しているタスクの前後にWinAppDriverの開始タスクと終了タスクを挿入する必要があるということです。 WinAppDriverの開始タスクではAgentResolutionとして'1080p'を指定します。(これ重要らしい) - task: Windows Application Driver@0 inputs: OperationType: 'Start' AgentResolution: '1080p' - task: CmdLine@2 displayName: "NUnit & OpenCover" inputs: script: > packages\OpenCover.4.7.1221\tools\OpenCover.Console.exe -register:Path64 -target:"packages\NUnit.ConsoleRunner.3.12.0\tools\nunit3-console.exe" -targetargs:"boilersGraphics.Test.dll" -targetdir:"boilersGraphics.Test\bin\$(buildConfiguration)" -returntargetcode -output:"coverage.xml" -filter:"+[boilersGraphics]* +[TsOperationHistory]* -[*]XamlGeneratedNamespace*" - task: Windows Application Driver@0 condition: always() inputs: OperationType: 'Stop' パイプライン実行 さて、これで舞台は整いました。 パイプラインを実行させてみましょう。 ↓パイプラインを実行させた結果がこちら。 2021-11-24T11:48:55.9989796Z ##[section]Starting: NUnit & OpenCover 2021-11-24T11:48:56.0729655Z ============================================================================== 2021-11-24T11:48:56.0730435Z Task : Command line 2021-11-24T11:48:56.0730929Z Description : Run a command line script using Bash on Linux and macOS and cmd.exe on Windows 2021-11-24T11:48:56.0731430Z Version : 2.182.0 2021-11-24T11:48:56.0731805Z Author : Microsoft Corporation 2021-11-24T11:48:56.0732276Z Help : https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/command-line 2021-11-24T11:48:56.0732806Z ============================================================================== 2021-11-24T11:48:57.1787288Z Generating script. 2021-11-24T11:48:57.1888785Z Script contents: 2021-11-24T11:48:57.1893206Z packages\OpenCover.4.7.1221\tools\OpenCover.Console.exe -register:Path64 -target:"packages\NUnit.ConsoleRunner.3.12.0\tools\nunit3-console.exe" -targetargs:"boilersGraphics.Test.dll" -targetdir:"boilersGraphics.Test\bin\Release" -returntargetcode -output:"coverage.xml" -filter:"+[boilersGraphics]* +[TsOperationHistory]* -[*]XamlGeneratedNamespace*" 2021-11-24T11:48:57.2258869Z ========================== Starting Command Output =========================== 2021-11-24T11:48:57.2537767Z ##[command]"C:\Windows\system32\cmd.exe" /D /E:ON /V:OFF /S /C "CALL "D:\a\_temp\7e2a093a-25f1-4ff7-abf1-566cc75afe9c.cmd"" 2021-11-24T11:48:57.5155667Z Launching OpenCover 4.7.1221.0 2021-11-24T11:48:58.9759009Z Executing: D:\a\1\s\packages\NUnit.ConsoleRunner.3.12.0\tools\nunit3-console.exe 2021-11-24T11:49:03.2922180Z NUnit Console Runner 3.12.0 (.NET 2.0) 2021-11-24T11:49:03.2923727Z Copyright (c) 2021 Charlie Poole, Rob Prouse 2021-11-24T11:49:03.3188109Z Wednesday, November 24, 2021 11:49:03 AM 2021-11-24T11:49:03.3195344Z 2021-11-24T11:49:09.3746263Z Runtime Environment 2021-11-24T11:49:09.3762571Z OS Version: Microsoft Windows NT 6.2.9200.0 2021-11-24T11:49:09.3763546Z Runtime: .NET Framework CLR v4.0.30319.42000 2021-11-24T11:49:09.3764423Z 2021-11-24T11:49:09.3766967Z Test Files 2021-11-24T11:49:09.3767678Z boilersGraphics.Test.dll 2021-11-24T11:49:09.3768279Z 2021-11-24T11:49:28.7292577Z 2021-11-24 11:49:27.3166|INFO|Homura.ORM.Migration.ChangePlanByVersion`1|Begin to upgrade to VersionOrigin. 2021-11-24T11:49:28.7294808Z 2021-11-24 11:49:27.6259|INFO|Homura.ORM.Migration.ChangePlanByVersion`1|Finish to upgrade to VersionOrigin. 2021-11-24T11:49:28.7308447Z 2021-11-24 11:49:27.6259|INFO|boilersGraphics.ViewModels.MainWindowViewModel|Heavy Modifying AppDB Count : 2 2021-11-24T11:49:28.7311356Z 2021-11-24 11:49:27.6259|INFO|boilersGraphics.Dao.SQLiteBaseDao`1|SQLite VACUUM Operation will start as soon. 2021-11-24T11:49:28.7324172Z 2021-11-24 11:49:27.6412|INFO|boilersGraphics.Dao.SQLiteBaseDao`1|SQLite VACUUM Operation finnished. 2021-11-24T11:49:29.0061038Z 2021-11-24 11:49:28.8550|INFO|boilersGraphics.ViewModels.MainWindowViewModel|Heavy Modifying AppDB Count : 0 (中略) 2021-11-24T11:50:59.6247511Z 2021-11-24 11:49:45.4339|INFO|boilersGraphics.Test.UITests.ExportTest|A 2021-11-24T11:50:59.6251058Z 2021-11-24 11:49:45.4339|INFO|boilersGraphics.Test.UITests.ExportTest|B 2021-11-24T11:50:59.6254031Z 2021-11-24 11:49:46.3341|INFO|boilersGraphics.Test.UITests.ExportTest|C 2021-11-24T11:50:59.6258212Z 2021-11-24 11:49:47.3152|INFO|boilersGraphics.Test.UITests.ExportTest|D 2021-11-24T11:50:59.6262441Z 2021-11-24 11:49:48.4392|INFO|boilersGraphics.Test.UITests.ExportTest|E 2021-11-24T11:50:59.6264755Z 2021-11-24 11:49:48.6446|INFO|boilersGraphics.Test.UITests.ExportTest|F 2021-11-24T11:50:59.6266893Z 2021-11-24 11:49:51.5246|INFO|boilersGraphics.Test.UITests.ExportTest|G 2021-11-24T11:50:59.6269610Z 2021-11-24 11:49:51.8636|INFO|boilersGraphics.Test.UITests.ExportTest|H 2021-11-24T11:50:59.6272604Z 2021-11-24 11:49:53.5064|INFO|boilersGraphics.Test.UITests.ExportTest|I 2021-11-24T11:50:59.6282263Z 2021-11-24 11:50:54.5629|INFO|boilersGraphics.Test.UITests.ExportTest|N 2021-11-24T11:50:59.6283830Z 2021-11-24 11:50:54.5629|INFO|boilersGraphics.Test.UITests.ExportTest|O 2021-11-24T11:51:08.3846661Z 2021-11-24 11:51:08.3303|INFO|boilersGraphics.Test.UITests.ExportTest|D:\a\1\s\boilersGraphics.Test\bin\Release\ExportTest.jpg (中略) 2021-11-24T11:51:12.3651621Z 2021-11-24T11:51:12.3669894Z Errors, Failures and Warnings 2021-11-24T11:51:12.3685461Z 2021-11-24T11:51:12.3734296Z 1) Error : boilersGraphics.Test.UITests.ExportTest.チェッカーパターンを読み込んでエクスポートする 2021-11-24T11:51:12.3746425Z OpenQA.Selenium.WebDriverException : The HTTP request to the remote WebDriver server for URL http://127.0.0.1:4723/session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848/element timed out after 60 seconds. 2021-11-24T11:51:12.3757425Z ----> System.Net.WebException : The operation has timed out 2021-11-24T11:51:12.3769726Z at OpenQA.Selenium.Appium.Service.AppiumCommandExecutor.Execute(Command commandToExecute) 2021-11-24T11:51:12.3781949Z at OpenQA.Selenium.Remote.RemoteWebDriver.Execute(String driverCommandToExecute, Dictionary`2 parameters) 2021-11-24T11:51:12.4721838Z at OpenQA.Selenium.Appium.AppiumDriver`1.Execute(String driverCommandToExecute, Dictionary`2 parameters) 2021-11-24T11:51:12.4914311Z at OpenQA.Selenium.Remote.RemoteWebDriver.FindElement(String mechanism, String value) 2021-11-24T11:51:12.4925116Z at OpenQA.Selenium.Appium.AppiumDriver`1.FindElement(String by, String value) 2021-11-24T11:51:12.4958725Z at OpenQA.Selenium.Appium.AppiumDriver`1.FindElementByAccessibilityId(String selector) 2021-11-24T11:51:12.5004117Z at boilersGraphics.Test.UITests.ExportTest.チェッカーパターンを読み込んでエクスポートする() in D:\a\1\s\boilersGraphics.Test\UITests\ExportTest.cs:line 64 2021-11-24T11:51:12.5021425Z --WebException 2021-11-24T11:51:12.5030030Z at System.Net.HttpWebRequest.GetResponse() 2021-11-24T11:51:12.5101834Z at OpenQA.Selenium.Remote.HttpCommandExecutor.MakeHttpRequest(HttpRequestInfo requestInfo) 2021-11-24T11:51:12.5102789Z 2021-11-24T11:51:12.5103905Z Run Settings 2021-11-24T11:51:12.5104752Z DisposeRunners: True 2021-11-24T11:51:12.5105614Z WorkDirectory: D:\a\1\s\boilersGraphics.Test\bin\Release 2021-11-24T11:51:12.5106484Z ImageRuntimeVersion: 4.0.30319 2021-11-24T11:51:12.5107345Z ImageTargetFrameworkName: .NETFramework,Version=v4.8 2021-11-24T11:51:12.5108254Z ImageRequiresX86: False 2021-11-24T11:51:12.5109122Z ImageRequiresDefaultAppDomainAssemblyResolver: False 2021-11-24T11:51:12.5109993Z TargetRuntimeFramework: net-4.0 2021-11-24T11:51:12.5110804Z NumberOfTestWorkers: 2 2021-11-24T11:51:12.5111509Z 2021-11-24T11:51:12.5112247Z Test Run Summary 2021-11-24T11:51:12.5113219Z Overall result: Failed 2021-11-24T11:51:12.5114161Z Test Count: 124, Passed: 123, Failed: 1, Warnings: 0, Inconclusive: 0, Skipped: 0 2021-11-24T11:51:12.5115134Z Failed Tests - Failures: 0, Errors: 1, Invalid: 0 2021-11-24T11:51:12.5115994Z Start time: 2021-11-24 11:49:09Z 2021-11-24T11:51:12.5116819Z End time: 2021-11-24 11:51:12Z 2021-11-24T11:51:12.5117916Z Duration: 122.680 seconds 2021-11-24T11:51:12.5118585Z 2021-11-24T11:51:12.5119861Z Results (nunit3) saved as TestResult.xml 2021-11-24T11:51:12.6175191Z Committing... 2021-11-24T11:51:12.8990731Z Visited Classes 130 of 418 (31.1) 2021-11-24T11:51:12.8992408Z Visited Methods 953 of 3041 (31.34) 2021-11-24T11:51:12.8993394Z Visited Points 2723 of 11774 (23.13) 2021-11-24T11:51:12.8994213Z Visited Branches 1234 of 5860 (21.06) 2021-11-24T11:51:12.8994783Z 2021-11-24T11:51:12.8995591Z ==== Alternative Results (includes all methods including those without corresponding source) ==== 2021-11-24T11:51:12.8996481Z Alternative Visited Classes 130 of 441 (29.48) 2021-11-24T11:51:12.8997281Z Alternative Visited Methods 953 of 3530 (27) 2021-11-24T11:51:13.0756701Z ##[error]Cmd.exe exited with code '1'. 2021-11-24T11:51:13.1410544Z ##[section]Finishing: NUnit & OpenCover テストが失敗してしまいました。 ログには以下のように出力されています。 A B C D E F G H I N O 処理ABCDEFGHIまでは順調に実行できているようです。 処理JKLMが実行できていない。Jで例外が飛んだか? 処理NOはfinally句なので実行されてますね。 ちなみにCloseの方のWinAppDriverタスクを見てみると、WinAppDriverのログが出力されています。 2021-11-24T11:51:13.1518574Z ##[section]Starting: WindowsApplicationDriver 2021-11-24T11:51:13.1864748Z ============================================================================== 2021-11-24T11:51:13.1866690Z Task : WinAppDriver 2021-11-24T11:51:13.1867990Z Description : Use this extention to integrate Windows Application Driver (WinAppDriver) into your Azure Pipeline. 2021-11-24T11:51:13.1870055Z Version : 0.0.2 2021-11-24T11:51:13.1871000Z Author : Microsoft 2021-11-24T11:51:13.1871980Z Help : Checkout the WinAppDriver GitHub Repo to learn more - https://github.com/Microsoft/WinAppDriver 2021-11-24T11:51:13.1873744Z ============================================================================== 2021-11-24T11:51:14.5302212Z Attempting to close WinAppDriver on Agent 2021-11-24T11:51:24.5349173Z 2021-11-24T11:51:24.5359197Z Printing WinAppDriver Console logs: 2021-11-24T11:51:24.5363875Z 2021-11-24T11:51:24.5442258Z Windows Application Driver listening for requests at: http://127.0.0.1:4723/ 2021-11-24T11:51:24.5447996Z Press ENTER to exit. 2021-11-24T11:51:24.5449264Z 2021-11-24T11:51:24.5449720Z 2021-11-24T11:51:24.5451412Z ========================================== 2021-11-24T11:51:24.5452118Z POST /session HTTP/1.1 2021-11-24T11:51:24.5452847Z 2021-11-24T11:51:24.5453768Z Accept: application/json, image/png 2021-11-24T11:51:24.5454281Z 2021-11-24T11:51:24.5455037Z Connection: Keep-Alive 2021-11-24T11:51:24.5455334Z 2021-11-24T11:51:24.5456373Z Content-Length: 152 2021-11-24T11:51:24.5457095Z 2021-11-24T11:51:24.5457864Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.5458492Z 2021-11-24T11:51:24.5460144Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.5461243Z 2021-11-24T11:51:24.5462525Z 2021-11-24T11:51:24.5463621Z 2021-11-24T11:51:24.5465046Z {"desiredCapabilities":{"app":"D:\\a\\1\\s\\boilersGraphics.Test\\bin\\Release\\boilersGraphics.exe","deviceName":"WindowsPC","platformName":"Windows"}} 2021-11-24T11:51:24.5466254Z HTTP/1.1 200 OK 2021-11-24T11:51:24.5466857Z 2021-11-24T11:51:24.5467789Z Content-Length: 175 2021-11-24T11:51:24.5468617Z 2021-11-24T11:51:24.5469832Z Content-Type: application/json 2021-11-24T11:51:24.5470574Z 2021-11-24T11:51:24.5471535Z 2021-11-24T11:51:24.5472467Z 2021-11-24T11:51:24.5474195Z {"sessionId":"DD6B692A-76CE-40AA-B4D1-6FDCB7E35848","status":0,"value":{"app":"D:\\a\\1\\s\\boilersGraphics.Test\\bin\\Release\\boilersGraphics.exe","platformName":"Windows"}} 2021-11-24T11:51:24.5475069Z 2021-11-24T11:51:24.5475892Z 2021-11-24T11:51:24.5479349Z ========================================== 2021-11-24T11:51:24.5663526Z POST /session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848/timeouts HTTP/1.1 2021-11-24T11:51:24.5667106Z 2021-11-24T11:51:24.5795302Z Accept: application/json, image/png 2021-11-24T11:51:24.5796146Z 2021-11-24T11:51:24.5796901Z Content-Length: 32 2021-11-24T11:51:24.5797431Z 2021-11-24T11:51:24.5798169Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.5798700Z 2021-11-24T11:51:24.5799408Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.5799926Z 2021-11-24T11:51:24.5800389Z 2021-11-24T11:51:24.5800869Z 2021-11-24T11:51:24.5801579Z {"type":"implicit","ms":60000.0} 2021-11-24T11:51:24.5802312Z HTTP/1.1 200 OK 2021-11-24T11:51:24.5802787Z 2021-11-24T11:51:24.5803600Z Content-Length: 63 2021-11-24T11:51:24.5804332Z 2021-11-24T11:51:24.5805167Z Content-Type: application/json 2021-11-24T11:51:24.5805674Z 2021-11-24T11:51:24.5806151Z 2021-11-24T11:51:24.5806602Z 2021-11-24T11:51:24.5807380Z {"sessionId":"DD6B692A-76CE-40AA-B4D1-6FDCB7E35848","status":0} 2021-11-24T11:51:24.5807988Z 2021-11-24T11:51:24.5808467Z 2021-11-24T11:51:24.5809180Z ========================================== 2021-11-24T11:51:24.5810010Z POST /session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848/window/current/maximize HTTP/1.1 2021-11-24T11:51:24.5810618Z 2021-11-24T11:51:24.5811323Z Accept: application/json, image/png 2021-11-24T11:51:24.5811827Z 2021-11-24T11:51:24.5812507Z Content-Length: 2 2021-11-24T11:51:24.5815141Z 2021-11-24T11:51:24.5815970Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.5816668Z 2021-11-24T11:51:24.5817374Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.5817889Z 2021-11-24T11:51:24.5818341Z 2021-11-24T11:51:24.5818822Z 2021-11-24T11:51:24.5819465Z {} 2021-11-24T11:51:24.5820125Z HTTP/1.1 200 OK 2021-11-24T11:51:24.5820596Z 2021-11-24T11:51:24.5821371Z Content-Length: 63 2021-11-24T11:51:24.5821927Z 2021-11-24T11:51:24.5822609Z Content-Type: application/json 2021-11-24T11:51:24.5823349Z 2021-11-24T11:51:24.5823986Z 2021-11-24T11:51:24.5824515Z 2021-11-24T11:51:24.5825340Z {"sessionId":"DD6B692A-76CE-40AA-B4D1-6FDCB7E35848","status":0} 2021-11-24T11:51:24.5826018Z 2021-11-24T11:51:24.5826537Z 2021-11-24T11:51:24.5858621Z ========================================== 2021-11-24T11:51:24.5859796Z POST /session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848/element HTTP/1.1 2021-11-24T11:51:24.5860412Z 2021-11-24T11:51:24.5861140Z Accept: application/json, image/png 2021-11-24T11:51:24.5861659Z 2021-11-24T11:51:24.5862349Z Content-Length: 43 2021-11-24T11:51:24.5862869Z 2021-11-24T11:51:24.5863677Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.5865258Z 2021-11-24T11:51:24.5865973Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.5866491Z 2021-11-24T11:51:24.5866942Z 2021-11-24T11:51:24.5867416Z 2021-11-24T11:51:24.5868144Z {"using":"accessibility id","value":"Load"} 2021-11-24T11:51:24.5868889Z HTTP/1.1 200 OK 2021-11-24T11:51:24.5869364Z 2021-11-24T11:51:24.5870256Z Content-Length: 101 2021-11-24T11:51:24.5870812Z 2021-11-24T11:51:24.5871562Z Content-Type: application/json 2021-11-24T11:51:24.5872105Z 2021-11-24T11:51:24.5872619Z 2021-11-24T11:51:24.5873103Z 2021-11-24T11:51:24.5874180Z {"sessionId":"DD6B692A-76CE-40AA-B4D1-6FDCB7E35848","status":0,"value":{"ELEMENT":"7.5860.33860402"}} 2021-11-24T11:51:24.5874927Z 2021-11-24T11:51:24.5875413Z 2021-11-24T11:51:24.5876184Z ========================================== 2021-11-24T11:51:24.5877098Z POST /session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848/element/7.5860.33860402/click HTTP/1.1 2021-11-24T11:51:24.5877781Z 2021-11-24T11:51:24.5878666Z Accept: application/json, image/png 2021-11-24T11:51:24.5879239Z 2021-11-24T11:51:24.5880004Z Content-Length: 2 2021-11-24T11:51:24.5880529Z 2021-11-24T11:51:24.5881580Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.5882226Z 2021-11-24T11:51:24.5882907Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.5883471Z 2021-11-24T11:51:24.5883927Z 2021-11-24T11:51:24.5884402Z 2021-11-24T11:51:24.5885045Z {} 2021-11-24T11:51:24.5885908Z HTTP/1.1 200 OK 2021-11-24T11:51:24.5886421Z 2021-11-24T11:51:24.5887145Z Content-Length: 63 2021-11-24T11:51:24.5887786Z 2021-11-24T11:51:24.5888477Z Content-Type: application/json 2021-11-24T11:51:24.5888980Z 2021-11-24T11:51:24.5889457Z 2021-11-24T11:51:24.5889910Z 2021-11-24T11:51:24.5890911Z {"sessionId":"DD6B692A-76CE-40AA-B4D1-6FDCB7E35848","status":0} 2021-11-24T11:51:24.5891572Z 2021-11-24T11:51:24.5892062Z 2021-11-24T11:51:24.5893022Z ========================================== 2021-11-24T11:51:24.5893841Z POST /session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848/element HTTP/1.1 2021-11-24T11:51:24.5894367Z 2021-11-24T11:51:24.5895012Z Accept: application/json, image/png 2021-11-24T11:51:24.5895467Z 2021-11-24T11:51:24.5896080Z Content-Length: 40 2021-11-24T11:51:24.5896532Z 2021-11-24T11:51:24.5897190Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.5897747Z 2021-11-24T11:51:24.5898381Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.5898840Z 2021-11-24T11:51:24.5899264Z 2021-11-24T11:51:24.5899688Z 2021-11-24T11:51:24.5900351Z {"using":"accessibility id","value":"1"} 2021-11-24T11:51:24.5901034Z HTTP/1.1 200 OK 2021-11-24T11:51:24.5901478Z 2021-11-24T11:51:24.5902092Z Content-Length: 94 2021-11-24T11:51:24.5902522Z 2021-11-24T11:51:24.5903152Z Content-Type: application/json 2021-11-24T11:51:24.5903673Z 2021-11-24T11:51:24.5904877Z 2021-11-24T11:51:24.5905311Z 2021-11-24T11:51:24.5906109Z {"sessionId":"DD6B692A-76CE-40AA-B4D1-6FDCB7E35848","status":0,"value":{"ELEMENT":"42.66074"}} 2021-11-24T11:51:24.5906834Z 2021-11-24T11:51:24.5907261Z 2021-11-24T11:51:24.5907917Z ========================================== 2021-11-24T11:51:24.5908702Z POST /session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848/element/42.66074/click HTTP/1.1 2021-11-24T11:51:24.5909236Z 2021-11-24T11:51:24.5909880Z Accept: application/json, image/png 2021-11-24T11:51:24.5910405Z 2021-11-24T11:51:24.5911657Z Content-Length: 2 2021-11-24T11:51:24.5912234Z 2021-11-24T11:51:24.5912941Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.5913556Z 2021-11-24T11:51:24.5914197Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.5914639Z 2021-11-24T11:51:24.5915061Z 2021-11-24T11:51:24.5915456Z 2021-11-24T11:51:24.5916151Z {} 2021-11-24T11:51:24.5916763Z HTTP/1.1 200 OK 2021-11-24T11:51:24.5917215Z 2021-11-24T11:51:24.5917838Z Content-Length: 63 2021-11-24T11:51:24.5918303Z 2021-11-24T11:51:24.5918946Z Content-Type: application/json 2021-11-24T11:51:24.5919435Z 2021-11-24T11:51:24.5919830Z 2021-11-24T11:51:24.5920250Z 2021-11-24T11:51:24.5920973Z {"sessionId":"DD6B692A-76CE-40AA-B4D1-6FDCB7E35848","status":0} 2021-11-24T11:51:24.5921539Z 2021-11-24T11:51:24.5921958Z 2021-11-24T11:51:24.5922610Z ========================================== 2021-11-24T11:51:24.5923439Z POST /session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848/keys HTTP/1.1 2021-11-24T11:51:24.5923942Z 2021-11-24T11:51:24.5924589Z Accept: application/json, image/png 2021-11-24T11:51:24.5925064Z 2021-11-24T11:51:24.5925680Z Content-Length: 27 2021-11-24T11:51:24.5926111Z 2021-11-24T11:51:24.5926774Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.5927267Z 2021-11-24T11:51:24.5927894Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.5928325Z 2021-11-24T11:51:24.5928749Z 2021-11-24T11:51:24.5929143Z 2021-11-24T11:51:24.5929858Z {"value":["","N",""]} 2021-11-24T11:51:24.5930589Z HTTP/1.1 200 OK 2021-11-24T11:51:24.5931034Z 2021-11-24T11:51:24.5931683Z Content-Length: 63 2021-11-24T11:51:24.5932108Z 2021-11-24T11:51:24.5932825Z Content-Type: application/json 2021-11-24T11:51:24.5933386Z 2021-11-24T11:51:24.5933788Z 2021-11-24T11:51:24.5934493Z 2021-11-24T11:51:24.5935268Z {"sessionId":"DD6B692A-76CE-40AA-B4D1-6FDCB7E35848","status":0} 2021-11-24T11:51:24.5935866Z 2021-11-24T11:51:24.5936329Z 2021-11-24T11:51:24.5937036Z ========================================== 2021-11-24T11:51:24.5937844Z POST /session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848/keys HTTP/1.1 2021-11-24T11:51:24.5938378Z 2021-11-24T11:51:24.5939070Z Accept: application/json, image/png 2021-11-24T11:51:24.5939582Z 2021-11-24T11:51:24.5940253Z Content-Length: 27 2021-11-24T11:51:24.5940717Z 2021-11-24T11:51:24.5941427Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.5941959Z 2021-11-24T11:51:24.5942627Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.5943130Z 2021-11-24T11:51:24.5943684Z 2021-11-24T11:51:24.5944111Z 2021-11-24T11:51:24.5944810Z {"value":["","N",""]} 2021-11-24T11:51:24.5945535Z HTTP/1.1 200 OK 2021-11-24T11:51:24.5946119Z 2021-11-24T11:51:24.5946769Z Content-Length: 63 2021-11-24T11:51:24.5947197Z 2021-11-24T11:51:24.5947835Z Content-Type: application/json 2021-11-24T11:51:24.5948305Z 2021-11-24T11:51:24.5948699Z 2021-11-24T11:51:24.5949121Z 2021-11-24T11:51:24.5949843Z {"sessionId":"DD6B692A-76CE-40AA-B4D1-6FDCB7E35848","status":0} 2021-11-24T11:51:24.5950441Z 2021-11-24T11:51:24.5950871Z 2021-11-24T11:51:24.5951517Z ========================================== 2021-11-24T11:51:24.5952264Z POST /session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848/element HTTP/1.1 2021-11-24T11:51:24.5952780Z 2021-11-24T11:51:24.5953503Z Accept: application/json, image/png 2021-11-24T11:51:24.5953994Z 2021-11-24T11:51:24.5954598Z Content-Length: 43 2021-11-24T11:51:24.5955053Z 2021-11-24T11:51:24.5955709Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.5956380Z 2021-11-24T11:51:24.5957017Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.5957610Z 2021-11-24T11:51:24.5958009Z 2021-11-24T11:51:24.5958435Z 2021-11-24T11:51:24.5959106Z {"using":"accessibility id","value":"1148"} 2021-11-24T11:51:24.5959793Z HTTP/1.1 200 OK 2021-11-24T11:51:24.5960214Z 2021-11-24T11:51:24.5960832Z Content-Length: 94 2021-11-24T11:51:24.5961284Z 2021-11-24T11:51:24.5961921Z Content-Type: application/json 2021-11-24T11:51:24.5962368Z 2021-11-24T11:51:24.5962790Z 2021-11-24T11:51:24.5963184Z 2021-11-24T11:51:24.5964264Z {"sessionId":"DD6B692A-76CE-40AA-B4D1-6FDCB7E35848","status":0,"value":{"ELEMENT":"42.66092"}} 2021-11-24T11:51:24.5964872Z 2021-11-24T11:51:24.5965266Z 2021-11-24T11:51:24.5965913Z ========================================== 2021-11-24T11:51:24.5966679Z POST /session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848/element/42.66092/value HTTP/1.1 2021-11-24T11:51:24.5967232Z 2021-11-24T11:51:24.5967954Z Accept: application/json, image/png 2021-11-24T11:51:24.5968414Z 2021-11-24T11:51:24.5969034Z Content-Length: 92 2021-11-24T11:51:24.5969477Z 2021-11-24T11:51:24.5970940Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.5971425Z 2021-11-24T11:51:24.5972049Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.5972508Z 2021-11-24T11:51:24.5972932Z 2021-11-24T11:51:24.5973423Z 2021-11-24T11:51:24.5974169Z {"value":["D:\\a\\1\\s\\boilersGraphics.Test\\bin\\Release\\XmlFiles\\checker_pattern.xml"]} 2021-11-24T11:51:24.5974930Z HTTP/1.1 200 OK 2021-11-24T11:51:24.5975367Z 2021-11-24T11:51:24.5975978Z Content-Length: 63 2021-11-24T11:51:24.5976408Z 2021-11-24T11:51:24.5977035Z Content-Type: application/json 2021-11-24T11:51:24.5977494Z 2021-11-24T11:51:24.5977891Z 2021-11-24T11:51:24.5978309Z 2021-11-24T11:51:24.5979019Z {"sessionId":"DD6B692A-76CE-40AA-B4D1-6FDCB7E35848","status":0} 2021-11-24T11:51:24.5979538Z 2021-11-24T11:51:24.5979950Z 2021-11-24T11:51:24.5980590Z ========================================== 2021-11-24T11:51:24.5981336Z POST /session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848/element HTTP/1.1 2021-11-24T11:51:24.5981835Z 2021-11-24T11:51:24.5982469Z Accept: application/json, image/png 2021-11-24T11:51:24.5982936Z 2021-11-24T11:51:24.5983633Z Content-Length: 40 2021-11-24T11:51:24.5984064Z 2021-11-24T11:51:24.5984821Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.5985307Z 2021-11-24T11:51:24.5985927Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.5986359Z 2021-11-24T11:51:24.5986775Z 2021-11-24T11:51:24.5987168Z 2021-11-24T11:51:24.5987827Z {"using":"accessibility id","value":"1"} 2021-11-24T11:51:24.5988501Z HTTP/1.1 200 OK 2021-11-24T11:51:24.5988937Z 2021-11-24T11:51:24.5989564Z Content-Length: 94 2021-11-24T11:51:24.5989994Z 2021-11-24T11:51:24.5990644Z Content-Type: application/json 2021-11-24T11:51:24.5991089Z 2021-11-24T11:51:24.5991485Z 2021-11-24T11:51:24.5991900Z 2021-11-24T11:51:24.5992669Z {"sessionId":"DD6B692A-76CE-40AA-B4D1-6FDCB7E35848","status":0,"value":{"ELEMENT":"42.66106"}} 2021-11-24T11:51:24.5993355Z 2021-11-24T11:51:24.5993759Z 2021-11-24T11:51:24.5994403Z ========================================== 2021-11-24T11:51:24.5995169Z POST /session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848/element/42.66106/click HTTP/1.1 2021-11-24T11:51:24.5995716Z 2021-11-24T11:51:24.5996352Z Accept: application/json, image/png 2021-11-24T11:51:24.5996805Z 2021-11-24T11:51:24.5997410Z Content-Length: 2 2021-11-24T11:51:24.5997853Z 2021-11-24T11:51:24.5998505Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.5998977Z 2021-11-24T11:51:24.5999592Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.6000046Z 2021-11-24T11:51:24.6000437Z 2021-11-24T11:51:24.6000936Z 2021-11-24T11:51:24.6001518Z {} 2021-11-24T11:51:24.6002111Z HTTP/1.1 200 OK 2021-11-24T11:51:24.6002526Z 2021-11-24T11:51:24.6003134Z Content-Length: 63 2021-11-24T11:51:24.6003663Z 2021-11-24T11:51:24.6004296Z Content-Type: application/json 2021-11-24T11:51:24.6004903Z 2021-11-24T11:51:24.6005319Z 2021-11-24T11:51:24.6005820Z 2021-11-24T11:51:24.6006558Z {"sessionId":"DD6B692A-76CE-40AA-B4D1-6FDCB7E35848","status":0} 2021-11-24T11:51:24.6007095Z 2021-11-24T11:51:24.6007515Z 2021-11-24T11:51:24.6008165Z ========================================== 2021-11-24T11:51:24.6008910Z POST /session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848/element HTTP/1.1 2021-11-24T11:51:24.6009399Z 2021-11-24T11:51:24.6010032Z Accept: application/json, image/png 2021-11-24T11:51:24.6010495Z 2021-11-24T11:51:24.6011107Z Content-Length: 45 2021-11-24T11:51:24.6011533Z 2021-11-24T11:51:24.6012188Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.6012670Z 2021-11-24T11:51:24.6013366Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.6013810Z 2021-11-24T11:51:24.6014225Z 2021-11-24T11:51:24.6014620Z 2021-11-24T11:51:24.6015286Z {"using":"accessibility id","value":"Export"} 2021-11-24T11:51:24.6015961Z HTTP/1.1 200 OK 2021-11-24T11:51:24.6016399Z 2021-11-24T11:51:24.6017006Z Content-Length: 101 2021-11-24T11:51:24.6017525Z 2021-11-24T11:51:24.6018158Z Content-Type: application/json 2021-11-24T11:51:24.6018622Z 2021-11-24T11:51:24.6019012Z 2021-11-24T11:51:24.6019426Z 2021-11-24T11:51:24.6020205Z {"sessionId":"DD6B692A-76CE-40AA-B4D1-6FDCB7E35848","status":0,"value":{"ELEMENT":"7.5860.27762102"}} 2021-11-24T11:51:24.6020801Z 2021-11-24T11:51:24.6021250Z 2021-11-24T11:51:24.6021894Z ========================================== 2021-11-24T11:51:24.6022685Z POST /session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848/element/7.5860.27762102/click HTTP/1.1 2021-11-24T11:51:24.6023301Z 2021-11-24T11:51:24.6023967Z Accept: application/json, image/png 2021-11-24T11:51:24.6024416Z 2021-11-24T11:51:24.6025031Z Content-Length: 2 2021-11-24T11:51:24.6025456Z 2021-11-24T11:51:24.6026104Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.6026589Z 2021-11-24T11:51:24.6027201Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.6027643Z 2021-11-24T11:51:24.6028062Z 2021-11-24T11:51:24.6028460Z 2021-11-24T11:51:24.6029038Z {} 2021-11-24T11:51:24.6029628Z HTTP/1.1 200 OK 2021-11-24T11:51:24.6030057Z 2021-11-24T11:51:24.6030667Z Content-Length: 63 2021-11-24T11:51:24.6031096Z 2021-11-24T11:51:24.6031720Z Content-Type: application/json 2021-11-24T11:51:24.6032180Z 2021-11-24T11:51:24.6032574Z 2021-11-24T11:51:24.6032985Z 2021-11-24T11:51:24.6033769Z {"sessionId":"DD6B692A-76CE-40AA-B4D1-6FDCB7E35848","status":0} 2021-11-24T11:51:24.6034378Z 2021-11-24T11:51:24.6034801Z 2021-11-24T11:51:24.6035439Z ========================================== 2021-11-24T11:51:24.6036401Z POST /session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848/element HTTP/1.1 2021-11-24T11:51:24.6036936Z 2021-11-24T11:51:24.6037623Z Accept: application/json, image/png 2021-11-24T11:51:24.6038132Z 2021-11-24T11:51:24.6038787Z Content-Length: 53 2021-11-24T11:51:24.6039246Z 2021-11-24T11:51:24.6039949Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.6040478Z 2021-11-24T11:51:24.6041164Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.6041640Z 2021-11-24T11:51:24.6042090Z 2021-11-24T11:51:24.6042518Z 2021-11-24T11:51:24.6043335Z {"using":"accessibility id","value":"ExportFileName"} 2021-11-24T11:51:24.6043907Z 2021-11-24T11:51:24.6044335Z 2021-11-24T11:51:24.6045032Z ========================================== 2021-11-24T11:51:24.6045825Z DELETE /session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848 HTTP/1.1 2021-11-24T11:51:24.6046365Z 2021-11-24T11:51:24.6047046Z Accept: application/json, image/png 2021-11-24T11:51:24.6047531Z 2021-11-24T11:51:24.6048195Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.6048677Z 2021-11-24T11:51:24.6049111Z 2021-11-24T11:51:24.6049558Z 2021-11-24T11:51:24.6049984Z 2021-11-24T11:51:24.6050629Z HTTP/1.1 200 OK 2021-11-24T11:51:24.6051289Z 2021-11-24T11:51:24.6051909Z Content-Length: 12 2021-11-24T11:51:24.6052339Z 2021-11-24T11:51:24.6052964Z Content-Type: application/json 2021-11-24T11:51:24.6054192Z 2021-11-24T11:51:24.6054598Z 2021-11-24T11:51:24.6055018Z 2021-11-24T11:51:24.6055749Z {"status":0} 2021-11-24T11:51:24.6056171Z 2021-11-24T11:51:24.6056565Z 2021-11-24T11:51:24.6057208Z ========================================== 2021-11-24T11:51:24.6057891Z POST /session HTTP/1.1 2021-11-24T11:51:24.6058394Z 2021-11-24T11:51:24.6059053Z Accept: application/json, image/png 2021-11-24T11:51:24.6540533Z 2021-11-24T11:51:24.6545137Z Content-Length: 152 2021-11-24T11:51:24.6618340Z 2021-11-24T11:51:24.6622425Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.6623086Z 2021-11-24T11:51:24.6624009Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.6624504Z 2021-11-24T11:51:24.6624913Z 2021-11-24T11:51:24.6625349Z 2021-11-24T11:51:24.6625760Z 2021-11-24T11:51:24.6626399Z HTTP/1.1 200 OK 2021-11-24T11:51:24.6626856Z 2021-11-24T11:51:24.6627485Z Content-Length: 175 2021-11-24T11:51:24.6627923Z 2021-11-24T11:51:24.6628564Z Content-Type: application/json 2021-11-24T11:51:24.6629059Z 2021-11-24T11:51:24.6629464Z 2021-11-24T11:51:24.6629869Z 2021-11-24T11:51:24.6630977Z {"sessionId":"98111BD1-7BA2-4F31-8515-8A4944BF4934","status":0,"value":{"app":"D:\\a\\1\\s\\boilersGraphics.Test\\bin\\Release\\boilersGraphics.exe","platformName":"Windows"}} 2021-11-24T11:51:24.6631768Z 2021-11-24T11:51:24.6632195Z 2021-11-24T11:51:24.6632855Z ========================================== 2021-11-24T11:51:24.6633674Z POST /session/98111BD1-7BA2-4F31-8515-8A4944BF4934/timeouts HTTP/1.1 2021-11-24T11:51:24.6634389Z 2021-11-24T11:51:24.6635057Z Accept: application/json, image/png 2021-11-24T11:51:24.6635521Z 2021-11-24T11:51:24.6636147Z Content-Length: 32 2021-11-24T11:51:24.6636605Z 2021-11-24T11:51:24.6637270Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.6637754Z 2021-11-24T11:51:24.6638381Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.6638860Z 2021-11-24T11:51:24.6639281Z 2021-11-24T11:51:24.6639694Z 2021-11-24T11:51:24.6640425Z {"type":"implicit","ms":60000.0} 2021-11-24T11:51:24.6642995Z HTTP/1.1 200 OK 2021-11-24T11:51:24.6646740Z 2021-11-24T11:51:24.6649187Z Content-Length: 63 2021-11-24T11:51:24.6651905Z 2021-11-24T11:51:24.6652782Z Content-Type: application/json 2021-11-24T11:51:24.6653493Z 2021-11-24T11:51:24.6653963Z 2021-11-24T11:51:24.6654421Z 2021-11-24T11:51:24.6655258Z {"sessionId":"98111BD1-7BA2-4F31-8515-8A4944BF4934","status":0} 2021-11-24T11:51:24.6655861Z 2021-11-24T11:51:24.6656330Z 2021-11-24T11:51:24.6657055Z ========================================== 2021-11-24T11:51:24.6658043Z POST /session/98111BD1-7BA2-4F31-8515-8A4944BF4934/window/current/maximize HTTP/1.1 2021-11-24T11:51:24.6658645Z 2021-11-24T11:51:24.6659356Z Accept: application/json, image/png 2021-11-24T11:51:24.6659883Z 2021-11-24T11:51:24.6660561Z Content-Length: 2 2021-11-24T11:51:24.6661049Z 2021-11-24T11:51:24.6661777Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.6662321Z 2021-11-24T11:51:24.6663011Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.6663624Z 2021-11-24T11:51:24.6664102Z 2021-11-24T11:51:24.6664555Z 2021-11-24T11:51:24.6665202Z {} 2021-11-24T11:51:24.6665872Z HTTP/1.1 200 OK 2021-11-24T11:51:24.6666364Z 2021-11-24T11:51:24.6667042Z Content-Length: 63 2021-11-24T11:51:24.6667540Z 2021-11-24T11:51:24.6668230Z Content-Type: application/json 2021-11-24T11:51:24.6668741Z 2021-11-24T11:51:24.6669177Z 2021-11-24T11:51:24.6669643Z 2021-11-24T11:51:24.6670437Z {"sessionId":"98111BD1-7BA2-4F31-8515-8A4944BF4934","status":0} 2021-11-24T11:51:24.6671018Z 2021-11-24T11:51:24.6671474Z 2021-11-24T11:51:24.6672169Z ========================================== 2021-11-24T11:51:24.6672980Z POST /session/98111BD1-7BA2-4F31-8515-8A4944BF4934/element HTTP/1.1 2021-11-24T11:51:24.6673622Z 2021-11-24T11:51:24.6674318Z Accept: application/json, image/png 2021-11-24T11:51:24.6674912Z 2021-11-24T11:51:24.6675612Z Content-Length: 45 2021-11-24T11:51:24.6676062Z 2021-11-24T11:51:24.6676719Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.6677380Z 2021-11-24T11:51:24.6678123Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.6678583Z 2021-11-24T11:51:24.6678988Z 2021-11-24T11:51:24.6679413Z 2021-11-24T11:51:24.6679812Z 2021-11-24T11:51:24.6680418Z HTTP/1.1 200 OK 2021-11-24T11:51:24.6681045Z 2021-11-24T11:51:24.6681708Z Content-Length: 101 2021-11-24T11:51:24.6682540Z 2021-11-24T11:51:24.6683231Z Content-Type: application/json 2021-11-24T11:51:24.6683841Z 2021-11-24T11:51:24.6684270Z 2021-11-24T11:51:24.6684699Z 2021-11-24T11:51:24.6685554Z {"sessionId":"98111BD1-7BA2-4F31-8515-8A4944BF4934","status":0,"value":{"ELEMENT":"7.2008.28475059"}} 2021-11-24T11:51:24.6686299Z 2021-11-24T11:51:24.6686713Z 2021-11-24T11:51:24.6687363Z ========================================== 2021-11-24T11:51:24.6688152Z POST /session/98111BD1-7BA2-4F31-8515-8A4944BF4934/element/7.2008.28475059/click HTTP/1.1 2021-11-24T11:51:24.6688692Z 2021-11-24T11:51:24.6689353Z Accept: application/json, image/png 2021-11-24T11:51:24.6689835Z 2021-11-24T11:51:24.6690457Z Content-Length: 2 2021-11-24T11:51:24.6691085Z 2021-11-24T11:51:24.6691908Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.6692373Z 2021-11-24T11:51:24.6692989Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.6693615Z 2021-11-24T11:51:24.6694055Z 2021-11-24T11:51:24.6694475Z 2021-11-24T11:51:24.6695052Z {} 2021-11-24T11:51:24.6695648Z HTTP/1.1 200 OK 2021-11-24T11:51:24.6696064Z 2021-11-24T11:51:24.6696675Z Content-Length: 63 2021-11-24T11:51:24.6697123Z 2021-11-24T11:51:24.6697750Z Content-Type: application/json 2021-11-24T11:51:24.6698195Z 2021-11-24T11:51:24.6698611Z 2021-11-24T11:51:24.6699006Z 2021-11-24T11:51:24.6699423Z 2021-11-24T11:51:24.6699821Z 2021-11-24T11:51:24.6700236Z 2021-11-24T11:51:24.6700875Z ========================================== 2021-11-24T11:51:24.6701616Z POST /session/98111BD1-7BA2-4F31-8515-8A4944BF4934/element HTTP/1.1 2021-11-24T11:51:24.6702120Z 2021-11-24T11:51:24.6702816Z Accept: application/json, image/png 2021-11-24T11:51:24.6703219Z 2021-11-24T11:51:24.6703841Z Content-Length: 53 2021-11-24T11:51:24.6704214Z 2021-11-24T11:51:24.6704784Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.6705206Z 2021-11-24T11:51:24.6705766Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.6706148Z 2021-11-24T11:51:24.6706496Z 2021-11-24T11:51:24.6706859Z 2021-11-24T11:51:24.6707459Z {"using":"accessibility id","value":"ExportFileName"} 2021-11-24T11:51:24.6708075Z HTTP/1.1 200 OK 2021-11-24T11:51:24.6708439Z 2021-11-24T11:51:24.6709054Z Content-Length: 100 2021-11-24T11:51:24.6709449Z 2021-11-24T11:51:24.6710004Z Content-Type: application/json 2021-11-24T11:51:24.6710393Z 2021-11-24T11:51:24.6710761Z 2021-11-24T11:51:24.6711105Z 2021-11-24T11:51:24.6712027Z {"sessionId":"98111BD1-7BA2-4F31-8515-8A4944BF4934","status":0,"value":{"ELEMENT":"7.2008.1107452"}} 2021-11-24T11:51:24.6712653Z 2021-11-24T11:51:24.6713126Z 2021-11-24T11:51:24.6713765Z ========================================== 2021-11-24T11:51:24.6714450Z POST /session/98111BD1-7BA2-4F31-8515-8A4944BF4934/element/7.2008.1107452/value HTTP/1.1 2021-11-24T11:51:24.6714943Z 2021-11-24T11:51:24.6715497Z Accept: application/json, image/png 2021-11-24T11:51:24.6715885Z 2021-11-24T11:51:24.6716439Z Content-Length: 77 2021-11-24T11:51:24.6716830Z 2021-11-24T11:51:24.6717397Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.6717804Z 2021-11-24T11:51:24.6718350Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.6718748Z 2021-11-24T11:51:24.6719093Z 2021-11-24T11:51:24.6719459Z 2021-11-24T11:51:24.6720078Z {"value":["D:\\a\\1\\s\\boilersGraphics.Test\\bin\\Release\\ExportTest.jpg"]} 2021-11-24T11:51:24.6720904Z HTTP/1.1 200 OK 2021-11-24T11:51:24.6721340Z 2021-11-24T11:51:24.6721975Z Content-Length: 63 2021-11-24T11:51:24.6722400Z 2021-11-24T11:51:24.6723030Z Content-Type: application/json 2021-11-24T11:51:24.6723565Z 2021-11-24T11:51:24.6723968Z 2021-11-24T11:51:24.6724634Z 2021-11-24T11:51:24.6725364Z {"sessionId":"98111BD1-7BA2-4F31-8515-8A4944BF4934","status":0} 2021-11-24T11:51:24.6725996Z 2021-11-24T11:51:24.6726412Z 2021-11-24T11:51:24.6727058Z ========================================== 2021-11-24T11:51:24.6727804Z POST /session/98111BD1-7BA2-4F31-8515-8A4944BF4934/element HTTP/1.1 2021-11-24T11:51:24.6728304Z 2021-11-24T11:51:24.6728942Z Accept: application/json, image/png 2021-11-24T11:51:24.6729406Z 2021-11-24T11:51:24.6730015Z Content-Length: 52 2021-11-24T11:51:24.6730439Z 2021-11-24T11:51:24.6731091Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.6731583Z 2021-11-24T11:51:24.6732200Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.6732639Z 2021-11-24T11:51:24.6733056Z 2021-11-24T11:51:24.6733734Z 2021-11-24T11:51:24.6734177Z 2021-11-24T11:51:24.6734782Z HTTP/1.1 200 OK 2021-11-24T11:51:24.6735202Z 2021-11-24T11:51:24.6735813Z Content-Length: 101 2021-11-24T11:51:24.6736263Z 2021-11-24T11:51:24.6736894Z Content-Type: application/json 2021-11-24T11:51:24.6737341Z 2021-11-24T11:51:24.6737763Z 2021-11-24T11:51:24.6738181Z 2021-11-24T11:51:24.6738968Z {"sessionId":"98111BD1-7BA2-4F31-8515-8A4944BF4934","status":0,"value":{"ELEMENT":"7.2008.35022440"}} 2021-11-24T11:51:24.6739771Z 2021-11-24T11:51:24.6740205Z 2021-11-24T11:51:24.6740922Z ========================================== 2021-11-24T11:51:24.6741867Z POST /session/98111BD1-7BA2-4F31-8515-8A4944BF4934/element/7.2008.35022440/click HTTP/1.1 2021-11-24T11:51:24.6742459Z 2021-11-24T11:51:24.6743146Z Accept: application/json, image/png 2021-11-24T11:51:24.6743750Z 2021-11-24T11:51:24.6744409Z Content-Length: 2 2021-11-24T11:51:24.6744874Z 2021-11-24T11:51:24.6745577Z Content-Type: application/json;charset=utf-8 2021-11-24T11:51:24.6746098Z 2021-11-24T11:51:24.6746764Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.6747236Z 2021-11-24T11:51:24.6747689Z 2021-11-24T11:51:24.6748120Z 2021-11-24T11:51:24.6748567Z 2021-11-24T11:51:24.6749226Z HTTP/1.1 200 OK 2021-11-24T11:51:24.6749678Z 2021-11-24T11:51:24.6750336Z Content-Length: 63 2021-11-24T11:51:24.6750820Z 2021-11-24T11:51:24.6751503Z Content-Type: application/json 2021-11-24T11:51:24.6751986Z 2021-11-24T11:51:24.6752435Z 2021-11-24T11:51:24.6752862Z 2021-11-24T11:51:24.6753710Z {"sessionId":"98111BD1-7BA2-4F31-8515-8A4944BF4934","status":0} 2021-11-24T11:51:24.6754305Z 2021-11-24T11:51:24.6754735Z 2021-11-24T11:51:24.6755428Z ========================================== 2021-11-24T11:51:24.6756248Z DELETE /session/98111BD1-7BA2-4F31-8515-8A4944BF4934 HTTP/1.1 2021-11-24T11:51:24.6756815Z 2021-11-24T11:51:24.6757483Z Accept: application/json, image/png 2021-11-24T11:51:24.6757990Z 2021-11-24T11:51:24.6758740Z Host: 127.0.0.1:4723 2021-11-24T11:51:24.6759212Z 2021-11-24T11:51:24.6759658Z 2021-11-24T11:51:24.6760084Z 2021-11-24T11:51:24.6760532Z 2021-11-24T11:51:24.6761252Z HTTP/1.1 200 OK 2021-11-24T11:51:24.6761672Z 2021-11-24T11:51:24.6762287Z Content-Length: 12 2021-11-24T11:51:24.6762732Z 2021-11-24T11:51:24.6763535Z Content-Type: application/json 2021-11-24T11:51:24.6763993Z 2021-11-24T11:51:24.6764406Z 2021-11-24T11:51:24.6764800Z 2021-11-24T11:51:24.6765399Z {"status":0} 2021-11-24T11:51:24.6807108Z ##[section]Finishing: WindowsApplicationDriver ここでtimeoutsになっているようです。 2021-11-24T11:51:24.5663526Z POST /session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848/timeouts HTTP/1.1 2021-11-24T11:51:12.3734296Z 1) Error : boilersGraphics.Test.UITests.ExportTest.チェッカーパターンを読み込んでエクスポートする 2021-11-24T11:51:12.3746425Z OpenQA.Selenium.WebDriverException : The HTTP request to the remote WebDriver server for URL http://127.0.0.1:4723/session/DD6B692A-76CE-40AA-B4D1-6FDCB7E35848/element timed out after 60 seconds. 2021-11-24T11:51:12.3757425Z ----> System.Net.WebException : The operation has timed out 2021-11-24T11:51:12.3769726Z at OpenQA.Selenium.Appium.Service.AppiumCommandExecutor.Execute(Command commandToExecute) 2021-11-24T11:51:12.3781949Z at OpenQA.Selenium.Remote.RemoteWebDriver.Execute(String driverCommandToExecute, Dictionary`2 parameters) 2021-11-24T11:51:12.4721838Z at OpenQA.Selenium.Appium.AppiumDriver`1.Execute(String driverCommandToExecute, Dictionary`2 parameters) 2021-11-24T11:51:12.4914311Z at OpenQA.Selenium.Remote.RemoteWebDriver.FindElement(String mechanism, String value) 2021-11-24T11:51:12.4925116Z at OpenQA.Selenium.Appium.AppiumDriver`1.FindElement(String by, String value) 2021-11-24T11:51:12.4958725Z at OpenQA.Selenium.Appium.AppiumDriver`1.FindElementByAccessibilityId(String selector) 2021-11-24T11:51:12.5004117Z at boilersGraphics.Test.UITests.ExportTest.チェッカーパターンを読み込んでエクスポートする() in D:\a\1\s\boilersGraphics.Test\UITests\ExportTest.cs:line 64 2021-11-24T11:51:12.5021425Z --WebException 2021-11-24T11:51:12.5030030Z at System.Net.HttpWebRequest.GetResponse() 2021-11-24T11:51:12.5101834Z at OpenQA.Selenium.Remote.HttpCommandExecutor.MakeHttpRequest(HttpRequestInfo requestInfo) 該当箇所はExportFileName(エクスポートウィンドウのFileName欄)を探している時にTimeoutになっているようです。 session.FindElementByAccessibilityId("ExportFileName").SendKeys(exportFilePath); これどうしたらいいんだろう...。 ソースコード ブランチは develop です。 まとめ というわけで、未完ですが、Azure DevOps & WinAppDriver の記事を書いてみましたよっと。 何か参考になれば幸いです。 宣伝 ベクターグラフィックスドローイングツールを開発しています。チェケラー コンピュータビジョンツールも開発しています。こちらは最近ご無沙汰ですが、たまにメンテしてます。スクリーンショット機能が便利でよく使ってますね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Gtk3アプリGtk.ListStoreを使ってコントロールを更新する

Gtk3アプリGtk.ListStoreを使ってコントロールを更新する Gtk.ListStoreを使いコントロールの更新を行います。 不特定の関数を作るのではなく、ListStoreのイベントハンドリングでまとめて更新をするとわかりやすくなります。 private Gtk.ListStore listStore1 = new Gtk.ListStore (typeof (testModel)); private void on_btn1_clicked(object sender , EventArgs e){ testModel testModel1 = new testModel(); testModel1.Name = "タイトル1"; testModel1.Description = "詳細1"; listStore1.Clear(); listStore1.AppendValues (testModel1); } private void _mkBining() { listStore1.RowChanged += delegate(object o, RowChangedArgs args) { ListStore testStore = ((ListStore)o); TreeIter iter; if (testStore.GetIter(out iter, args.Path)) { testModel testModel1 = (testModel)testStore.GetValue(iter, 0); Console.WriteLine("testModel1" + testModel1.icon_id ); titleEntry.Text = testModel1.Name; descriptionEntry.Text = testModel1.Description; } }; } ListStoreのRowChangedメソッドを使い、ListStoreが更新されたら他のコントロールを更新するようにします。 listStore1.RowChanged += delegate(object o, RowChangedArgs args) { ListStore testStore = ((ListStore)o); TreeIter iter; if (testStore.GetIter(out iter, args.Path)) { testModel testModel1 = (testModel)testStore.GetValue(iter, 0); } }; 続く
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityでカメラが近づくとモデルが消えてしまう時の対処法

カメラが近づいた際にモデルが消えてしまう現象が発生している・・・ モデルを設置する際には表示されるがなぜ近づくと消えてしまうのか。 解決方法 「Inspector」から「update whenoffscreen」にチェックマークをつける。英文の通り「オフスクリーン時に更新 見えない時もその処理を実行」キャラクターが多く出てくるプロジェクトには問題が発生してくる。 そのほかの対処法としては、「skinnedMeshRenderer」の「Bounds」の「Extent」ここを調整して大きくすれば表示される場合もある。 それでも解決されない場合 ・FileからBuild Settingを選択する ・PlatformからWebGLを選択し、Switch Platformを選択する。 結果 Unityで近づいてもモデルが消えて現象が解消されました。✨ 「Update when Offscreen」や「skinnedMeshRenderer」の「Bounds」の「Extent」を変更してもモデルが消えてしまう場合は、WebGLのみの対応なのか、どのプラットフォームに対応しているのか確認してみた方が良いのかもしれませんね〜!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【C#】配列、stringの内部実装とSpan<T>のありがたみ

はじめに C#で、組み込み型1にできてユーザー定義型ではできないことの一つに可変長の型の作成があります。 つまり、配列型(T[])と文字列型(string)は可変長の参照型という、特別扱いを受ける型なのです。 そこで、これらの型がメモリ上にどのように配置されるのかについて調べてみました。 調査 ポインタを用いて、stringとbyte[]のメモリ上での配置のされ方を実際に調べます。.NET6で実際に調べた結果ですので、すべての環境でこのようになることが保障されているわけではありません。ご了承ください。C#では参照型へのポインタはunsafeコンテキストでも禁止されていますが、Unsafeクラス(System.Runtime.CompilerServices名前空間)にあるメソッド群(Unsafe.AsやUnsafe.AsPointer)を駆使すると、強引にポインタ化できます。2 stringの内部実装 64bitの場合 (64bit OS , 64bit CPU , コンソールアプリケーション , x64ビルド) 開始アドレス 終了アドレス 長さ 内容 0 7 8 型情報 8 11 4 文字列長(Int32) 12 可変 文字数*2 文字データ(UTF-16) 終端 2 NULL文字 このようになっています。一般のstring型への参照が指し示すアドレスを0として、相対値で表記しています。 fixed(char* ptr = {string})のようにして得たchar*が指し示すのは文字データの開始アドレス、12ですので注意してください。 型情報は、RuntimeTypeのRuntimeTypeHandle (ドキュメント) を参照して得られるものと同じ値で、仮想関数テーブルへのアドレスのようです。この値は、ボックス化された値型を含めヒープ上に存在するすべての型に共通して存在します。 32bitの場合 (64bit OS , 64bit CPU , コンソールアプリケーション , x86ビルド) 開始アドレス 終了アドレス 長さ 内容 0 3 8 型情報 4 7 4 文字列長(Int32) 8 可変 文字数*2 文字データ(UTF-16) 終端 2 NULL文字 このようになっています。型情報はそれ自体ポインタなので、実行環境のポインタのサイズによりレイアウトが変わってしまうようです。 WebAssemblyの場合 64bitと同様です。WasmではIntPtrの大きさが4byteなので、少し不思議な感じです。 配列の内部実装 64bit nativeの場合 (64bit OS , 64bit CPU , コンソールアプリケーション , x64ビルド) 開始アドレス 終了アドレス 長さ 内容 0 7 8 型情報 8 11 4 配列長(Int32) 12 15 4 未使用領域 16 可変 配列長*sizeof(T) 生データ 配列はこのような構造になっています。生データのレイアウトを8の倍数に合わせるように未使用領域が入っているのだと思われます。 fixedして得られるアドレスはやはり生データの先頭アドレスであるので注意してください。この場合は16ずれます。 32bit nativeの場合 (64bit OS , 64bit CPU , コンソールアプリケーション , x86ビルド) 開始アドレス 終了アドレス 長さ 内容 0 3 4 型情報 4 7 4 配列長(Int32) 8 可変 配列長*sizeof(T) 生データ 型情報自体がポインタなので、全体的に小さくなりました。 WebAssemblyの場合 (64bit OS , 64bit CPU , WebAssembly , AOTなし) やはり64bitのときと同じレイアウトです。0ばっかり入ってすっかすかなレイアウトになります。 検証に使用したコード byte[]を調べるコードですが、全く同様に他の参照型も調べられます。 using System.Runtime.CompilerServices; using System.Runtime.InteropServices; unsafe { Console.WriteLine($"IntPtr:{IntPtr.Size}"); byte[] array = new byte[] { 1, 2, 3, 4, 5 }; var pointer = Unsafe.AsPointer(ref array); var arrayAddress = *(IntPtr*)pointer; var arrayFirst = (*(Hoge*)arrayAddress.ToPointer()); Console.WriteLine($"===trace array layout==={Environment.NewLine}{arrayFirst.ToString()}"); } [StructLayout(LayoutKind.Sequential)] struct Hoge { long field1; long field2; long field3; long field4; public override string ToString() { return $"{field1.ToString("x16")}{Environment.NewLine}{field2.ToString("x16")}{Environment.NewLine}{field3.ToString("x16")}{Environment.NewLine}{field4.ToString("x16")}"; } } 生データ little-endianなことに注意して読んで下さい。 64bit-native IntPtr:8 ===trace array layout=== 00007ff7b660fd50 0000000000000005 0000000504030201 0000000000000000 32bit-native IntPtr:4 ===trace array layout=== 0000000508a4d798 0000000504030201 0ab273cc00000000 0000000000000000 wasm IntPtr:4 ===trace array layout=== 0000000002e29d00 0000000500000000 0000000504030201 0000000000000000 stringはchar[]でないし、char[]はstringでない stringとchar[]の相互変換ができたらいいと思ったことは一度くらいはあるでしょう。もちろん値をすべてコピーすれば可能ですが、コピーなしでできるでしょうか? コピーなし再解釈の手法 unsafe.Asメソッドは、C#の型システムを破壊し、低レベルで型の解釈を変更します。メモリ上には何も手を加えず、単にC#上での型解釈だけが変わります(いったんvoid*にキャストしてから目的の型のポインタにキャストするイメージ)。メモリレイアウトが厳密に一致していれば、これでコピーなしで変換ができます。参照型を扱う場合は型情報の書き換えも必要です(超アンセーフ)。 もしstringをchar[]に再解釈したとすると、stringとchar[]では奇遇にも長さの表現が同じなので、長さは正しく認識されます。しかし、32bit環境以外ではstringにはない未使用領域がchar[]あるため、先頭の2文字は認識されません。そして、終端のnull文字とはみ出して2バイト分(!未定義動作)が末尾に追加されます。 逆もまたしかりで、char[]をstringとして解釈すると少なくとも意図したとおりにはなりません(はみだしはしないので幾分か安全)。やはり、stringとchar[]の相互変換ではコピーが避けられないのです。 byte[]はバイナリを抽象化しない 結局、配列とは、型情報・長さ・未使用領域・生データが一列に並んだ特殊なデータです。例えばbyte[]はバイナリを含みますが、任意のバイナリデータはbyte[]ではありません。文字列も同様に、任意のUTF-16の文字データの並びはstringではないのです。これはパフォーマンスが必要な場面では足かせになりうることは先ほど見た通りでしょう(必要なさそうなコピーを強いられる)。 解決できる型を作ろう 型情報と長さを生データと一緒に並べるという規約により不都合が生じたのですから、これらを分離可能にすれば解決できます。型情報を並べるというのも今どきの実装でないので、型情報はジェネリック型引数として持つ実装にしましょう。パフォーマンス向上のためにこの新しい型は構造体にします。 public unsafe struct Hoge<T> { private void* ptr; //生データへのポインタ private int length; //要素の長さ } そうして、Span<T>が再発明された。 出来上がった新しい型、それは(ほぼ)Span<T>だった。実際にはSpan<T>はマネージドな型になるように、void*は使っていませんしref制約が入りますが、そっくりです。 Span<T>は、高価なコピーコストをかけることなく、任意の生データを配列かのように扱うことができる、分離構造の型です。char[]もstringもReadOnlySpan<char>にできますし、その部分文字列もReadOnlySpan<T>にできます。もちろんこの変換は0コストに近いです。 C#での組み込み型の定義は様々ですが、ここではC#で専用の構文/キーワードを持つ型と、IL上専用命令を持つ型を組み込み型としています。 ↩ GCが発生し、コンパクションが走ると未定義動作になるので実験以外では行ってはいけません。 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【C#】CSVを1行ずつ読み込む方法

概要 C#でCSVファイルを1行ずつ処理したい時に少しハマったので、備忘録的にを残しておきます。 StreamReaderを利用する方法 これはググって最初に出てきた方法です。 C#でファイルを読み込む際はStreamReaderを使うのが普通のようです。 1行ずつ文字列として読み込んでカンマでsplitすれば要素を取得できます。 Program.CSと同じ階層に以下のようなCSVファイルがあるとします。 input.csv A1,A2,A2 B1,B2,B3 Program.CS using System; using System.IO; namespace TestReadingCsv { class Program { static void Main(string[] args) { using (StreamReader reader = new StreamReader(@"..\..\..\input.csv")) { while (!reader.EndOfStream) { string line = reader.ReadLine(); string[] values = line.Split(','); foreach (string value in values) Console.WriteLine(value); } } } } } 結果 A1 A2 A2 B1 B2 B3 問題点 しかし、この方法だと要素内にカンマや改行が含まれている時に期待する結果にはなりません。 また、CSVがダブルクォートで囲まれている形式だった場合にいちいち取り除く必要があり不便です。 ましてや、行によってダブルクォートが有ったり無かったりしたら面倒極まりないでしょう。 input.csv A1,"カンマ,が含まれた行",A2 "B1","改行 が含まれた行","B3" Program.CS using System; using System.IO; namespace TestReadingCsv { class Program { static void Main(string[] args) { using (StreamReader reader = new StreamReader(@"..\..\..\input.csv")) { while (!reader.EndOfStream) { string line = reader.ReadLine(); string[] values = line.Split(','); int i = 1; foreach (string value in values) Console.WriteLine(string.Format("{0}: {1}", i++, value)); } } } } } 結果 1: A1 2: "カンマ 3: が含まれた行" 4: A2 1: "B1" 2: "改行 1: が含まれた行" 2: "B3" TextFieldParserを利用する方法 このようなケースにぴったりのクラスがありました。それがTextFieldParserです。 要素内のカンマや改行に対応しています。また、ダブルクォートの有無が混在していても問題ありません。 (こっちを先に見つけていれば困ることもなかったのに・・・) Program.CS using System; using Microsoft.VisualBasic.FileIO; namespace TestReadingCsv { class Program { static void Main(string[] args) { using (TextFieldParser txtParser = new TextFieldParser(@"..\..\..\input.csv")) { txtParser.SetDelimiters(","); while (!txtParser.EndOfData) { string[] values = txtParser.ReadFields(); int i = 1; foreach (string value in values) Console.WriteLine(string.Format("{0}: {1}", i++, value)); } } } } } 結果 1: A1 2: カンマ,が含まれた行 3: A2 1: B1 2: 改行 が含まれた行 3: B3 まさにこれって感じですね。 区切り文字をタブ文字にすればTSVにも対応できます。 その他にもいくつか設定値があるので、うまく使いこなせばCSV以外のフォーマットでも使えそうです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【NUnit】テストケースを複数作る方法をまとめてみた

NUnit では、一つのテストメソッド内で複数テストケースを作ることができます。 そのための二つの属性の使い方をまとめてみました。 TestCase 基本形 TestCase 属性内に、メソッドに渡す引数を書きます。 TestCase のパターン分テストを実行してくれます。 using NUnit.Framework; public class Calculator { public int AddTwoNumbers(int x, int y) { return x + y; } } [TestFixture] public class CalculatorTest { private Calculator _calculator; [SetUp] public void SetUp() { _calculator = new Calculator(); } [TestCase(4, 2, 6)] [TestCase(9, 3, 12)] [TestCase(12, 3, 15)] public void AddTwoNumbers_ReturnTotal(int x, int y, int expected) { var result = _calculator.AddTwoNumbers(x, y); Assert.AreEqual(result, expected); } } 名前付きパラメータ ExpectedResult テストメソッド内で判定したい値を return させて使います。 属性内で期待結果を明示できるので、わかりやすいです。 using NUnit.Framework; public class Calculator { public int AddTwoNumbers(int x, int y) { return x + y; } } [TestFixture] public class CalculatorTest { private Calculator _calculator; [SetUp] public void SetUp() { _calculator = new Calculator(); } [TestCase(4, 2, ExpectedResult=6)] [TestCase(9, 3, ExpectedResult = 12)] [TestCase(12, 3, ExpectedResult = 15)] public int AddTwoNumbers_ReturnTotal(int x, int y) { var result = _calculator.AddTwoNumbers(x, y); return result; } } TestCaseSource 基本形 テストケースが多くなると、切り分けて管理したくなります。 そんなとき使えるのが、TestCaseSource 属性です。 なお、テストケースを生成するオブジェクトはプロパティや他クラス内のメソッドでも可能ですが、必ず static でなければなりません。 using NUnit.Framework; public class Calculator { public int AddTwoNumbers(int x, int y) { return x + y; } } [TestFixture] public class CalculatorTest { private Calculator _calculator; [SetUp] public void SetUp() { _calculator = new Calculator(); } [TestCaseSource(nameof(AddNumbersCases))] public void AddTwoNumbers_ReturnTotal(int x, int y, int expected) { var result = _calculator.AddTwoNumbers(x, y); Assert.AreEqual(result, expected); } static object[] AddNumbersCases = { new object[] { 4, 2, 6 }, new object[] { 9, 3, 12 }, new object[] { 12, 3, 15 } }; } テストケース生成をイテレーターとして定義する テストケースをイテレーターで定義することもできます。 ケースをメソッドごとに出し分けすることが可能になります。 using System.Collections.Generic; using NUnit.Framework; public class MyTestClass { // TestStrings の generateLongTestCase = True [TestCaseSource(nameof(TestStrings), new object[] { true })] public void LongNameWithEvenNumberOfCharacters(string name) { Assert.That(name.Length, Is.GreaterThan(5)); bool hasEvenNumOfCharacters = (name.Length / 2) == 0; } // TestStrings の generateLongTestCase = False [TestCaseSource(nameof(TestStrings), new object[] { false })] public void ShortName(string name) { Assert.That(name.Length, Is.LessThan(15)); } // テストケースを生成 // 出し分けの判定のための引数を持つ static IEnumerable<string> TestStrings(bool generateLongTestCase) { if (generateLongTestCase) // LongNameWithEvenNumberOfCharacters にのみ引数 name として渡される yield return "ThisIsAVeryLongNameThisIsAVeryLongName"; yield return "SomeName"; yield return "YetAnotherName"; } } 参照 https://docs.nunit.org/articles/nunit/writing-tests/attributes/testcase.html https://docs.nunit.org/articles/nunit/writing-tests/attributes/testcasesource.html
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む