1 2 |
CTime tm = CTime::GetCurrentTime(); CString strTm = tm.Format("%Y/%m/%d %H:%M:%S: "); |
参考サイト
CTime Class
https://msdn.microsoft.com/en-us/library/78zb0ese.aspx
最近はウェブ系アプリ中心、あとWindowsアプリちょっと
1 2 |
CTime tm = CTime::GetCurrentTime(); CString strTm = tm.Format("%Y/%m/%d %H:%M:%S: "); |
CTime Class
https://msdn.microsoft.com/en-us/library/78zb0ese.aspx
1 2 3 4 5 6 7 8 |
CStdioFile file; if (!file.Open(GetLogFileName(), CFile::modeCreate|CFile::modeNoTruncate|CFile::modeWrite|CFile::typeText)) { // fatal } file.SeekToEnd(); file.WriteString(szLog); file.Close(); |
CStdioFile Class
https://msdn.microsoft.com/en-us/library/a499td6y.aspx
UI Recorderという、テスト自動化のためのツールが公開されたらしい。UI Recorderを使うと、操作手順をキャプチャしてC#のコードを生成してくれるみたい。試してみる。
Microsoft、オープンソースの自動UIテストスクリプトツール「WinAppDriver UI Recorder」を公開:自動UIテストのスクリプトを簡単に作成できる – @IT
http://www.atmarkit.co.jp/ait/articles/1806/22/news036.html
WinAppDriver/Tools/UIRecorder at master · Microsoft/WinAppDriver · GitHub
https://github.com/Microsoft/WinAppDriver/tree/master/Tools/UIRecorder
1. リポジトリのクローニング
1 |
$ git clone https://github.com/Microsoft/WinAppDriver |
2. VS2017でソリューションファイルを開く
WinAppDriver\Tools\UIRecorder\WinAppDriverUIRecorder.sln
3. ビルド
ビルドしたらエラーが出た。
1 2 |
MSB8036: The Windows SDK version 10.0.16299.0 was not found. Install the required version of Windows SDK or change the SDK version in the project property pages or by right-clicking the solution and selecting "Retarget solution". |
プロジェクトにアサインされているバージョンのWindows SDKがこのマシン上には存在しないので、ソリューションを右クリックして[Retarget solution]を選択し、存在するバージョンに変更する。
1 2 3 4 |
Retarget Projects Select Windows SDK version for the following projects. Windows SDK Version: 10.0.17134.0 ..\UIXPathLib\UIXPathLib.vcxproj |
再ビルドして成功。
Windowsの電卓を操作して記録してみる。
1. UI Recorderを実行する。
2. [Record]ボタンをクリックして電卓アプリを操作する。
3. 操作完了したら[Stop Recording]ボタンをクリックする。
4. [C# Code]タブに操作内容のC#コードが生成される。
前処理 (WinAppDriverの起動やセッションの確立処理など)部分は参考サイトのコードをそのままコピペさせてもらって、それに続けてUIRecorderが生成したC#のコードを貼りつける。
1. プロジェクト作成 Console App (.NET Framework)
2. NuGetでAppium.WebDriver をインストールする
3. コーディング
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
using System; using OpenQA.Selenium.Appium.Windows; using OpenQA.Selenium.Remote; namespace CalcTest { class Program { private const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723"; private const string CalculatorAppId = "Microsoft.WindowsCalculator_8wekyb3d8bbwe!App"; protected static WindowsDriver<WindowsElement> session; static void Main(string[] args) { string serverPath = System.IO.Path.Combine( System.Environment.GetFolderPath( System.Environment.SpecialFolder.ProgramFilesX86 ), @"Windows Application Driver", "WinAppDriver.exe" ); System.Diagnostics.Process.Start(serverPath); DesiredCapabilities appCapabilities = new DesiredCapabilities(); appCapabilities.SetCapability("app", CalculatorAppId); session = new WindowsDriver<WindowsElement>(new Uri(WindowsApplicationDriverUrl), appCapabilities); session.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(1.5)); // LeftClick on "One" at (50,48) Console.WriteLine("LeftClick on \"One\" at (50,48)"); string xp1 = "//*[@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"NumberPad\"][@Name=\"Number pad\"]/Button[@AutomationId=\"num1Button\"][@Name=\"One\"]"; var winElem1 = session.FindElementByXPath(xp1); if (winElem1 != null) { winElem1.Click(); } else { Console.WriteLine($"Failed to find element {xp1}"); return; } // LeftClick on "Two" at (43,35) Console.WriteLine("LeftClick on \"Two\" at (43,35)"); string xp2 = "//*[@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"NumberPad\"][@Name=\"Number pad\"]/Button[@AutomationId=\"num2Button\"][@Name=\"Two\"]"; var winElem2 = session.FindElementByXPath(xp2); if (winElem2 != null) { winElem2.Click(); } else { Console.WriteLine($"Failed to find element {xp2}"); return; } // LeftClick on "Three" at (37,43) Console.WriteLine("LeftClick on \"Three\" at (37,43)"); string xp3 = "//*[@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"NumberPad\"][@Name=\"Number pad\"]/Button[@AutomationId=\"num3Button\"][@Name=\"Three\"]"; var winElem3 = session.FindElementByXPath(xp3); if (winElem3 != null) { winElem3.Click(); } else { Console.WriteLine($"Failed to find element {xp3}"); return; } // LeftClick on "Plus" at (46,45) Console.WriteLine("LeftClick on \"Plus\" at (46,45)"); string xp4 = "//*[@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"StandardOperators\"][@Name=\"Standard operators\"]/Button[@AutomationId=\"plusButton\"][@Name=\"Plus\"]"; var winElem4 = session.FindElementByXPath(xp4); if (winElem4 != null) { winElem4.Click(); } else { Console.WriteLine($"Failed to find element {xp4}"); return; } // LeftClick on "Six" at (40,40) Console.WriteLine("LeftClick on \"Six\" at (40,40)"); string xp5 = "//*[@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"NumberPad\"][@Name=\"Number pad\"]/Button[@AutomationId=\"num6Button\"][@Name=\"Six\"]"; var winElem5 = session.FindElementByXPath(xp5); if (winElem5 != null) { winElem5.Click(); } else { Console.WriteLine($"Failed to find element {xp5}"); return; } // LeftClick on "Equals" at (39,17) Console.WriteLine("LeftClick on \"Equals\" at (39,17)"); string xp6 = "//*[@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"StandardOperators\"][@Name=\"Standard operators\"]/Button[@AutomationId=\"equalButton\"][@Name=\"Equals\"]"; var winElem6 = session.FindElementByXPath(xp6); if (winElem6 != null) { winElem6.Click(); } else { Console.WriteLine($"Failed to find element {xp6}"); return; } } } } |
XPathはそのままだとNot Foundになるので、以下のように編集した。
編集前
1 |
string xp1 = "/Pane[@Name=\"Desktop 1\"][@ClassName=\"#32769\"]/Window[@Name=\"Calculator - Calculator\"][@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"NumberPad\"][@Name=\"Number pad\"]/Button[@AutomationId=\"num1Button\"][@Name=\"One\"]"; |
編集後
1 |
string xp1 = "//*[@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"NumberPad\"][@Name=\"Number pad\"]/Button[@AutomationId=\"num1Button\"][@Name=\"One\"]"; |
4. ビルドして実行
アプリが自動実行された。
WinAppDriver UI Recorderを試してみました。 | 初心者備忘録
https://www.ka-net.org/blog/?p=10504
Windows Application Driverは、WindowsアプリケーションにおけるSeleniumライクなUIテストオートメーションをサポートするサービス。このサービスは、Windows 10 PCを使ったUniversal Windows Platform (UWP)及びClassic Windows (Win32)アプリのテストをサポートしている。
GitHubで公開されているので試してみる。
GitHub – Microsoft/WinAppDriver: Windows Application Driver
https://github.com/Microsoft/WinAppDriver
1. ダウンロード https://github.com/Microsoft/WinAppDriver/releases
2. インストール
3. 実行する C:\Program Files (x86)\Windows Application Driver\WinAppDriver.exe
1. VS2017でSamples\C#\CalculatorTest.slnを開く
2. Test > Windows > Test Explorer を選択
3. Run All を選択してテスト実行
電卓アプリが自動で動くのが確認できた。
WinAppDriver: Selenium に似た Appium のテストを使用して、Windows であらゆるアプリのテストを実行 – Visual Studio 日本チーム Blog
https://blogs.msdn.microsoft.com/visualstudio_jpn/2016/12/02/winappdrivertestanyappwithappiumsseleniumliketestsonwindows/
Windowsアプリのテスト自動化ツールを探していたらFriendlyというオープンソースのライブラリが見つかった。どういう仕組みで動くのか試してみたい。このライブラリに言及した記事を探したら以下がヒット。書かれたのは2014年と古い記事なので、この記事をなぞって自分で試してみる。
Friendlyエバンジェリストはミニスカサンタ – xin9le.net
http://blog.xin9le.net/entry/2014/12/22/000057
なお、本家リポジトリはこちら。
GitHub – Codeer-Software/Friendly
https://github.com/Codeer-Software/Friendly
– Windows Form App (.NET Framework)
– テスト用にプロパティとメソッドを追加
Form1.cs
1 2 3 4 5 6 7 8 9 10 11 12 |
namespace SampleApp { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private readonly string xMas = "Hello there!"; private static string GetNow() => "Current time is \{DateTime.Now}."; } } |
– Console App (.NET Framework)
– Manage NuGet Packages…
– Codeer.Friendly by Codeer v.2.5.2
– Codeer.Friendly.Windows by Codeer v.2.9.0
Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Diagnostics; using System.Drawing; using System.Reflection; using System.Windows.Forms; // Codeer // https://www.codeer.co.jp/ using Codeer.Friendly.Dynamic; using Codeer.Friendly.Windows; namespace TestApp { class Program { // Friendlyを使ったテスト自動化 // 参考サイト: // Friendlyエバンジェリストはミニスカサンタ - xin9le.net // http://blog.xin9le.net/entry/2014/12/22/000057 static void Main(string[] args) { //--- プロセス起動 var path = @"D:\\Visual Studio 2017\\Projects\\SampleApp\\SampleApp\\bin\\Debug\\SampleApp.exe"; var process = Process.Start(path); //--- プロセスにアタッチ var targetApp = new WindowsAppFriend(process); //--- staticメソッドの呼び出し var now = targetApp.Type("SampleApp.Form1").GetNow(); Console.WriteLine(now); //--- プロパティの参照 var form = targetApp.Type<Application>().OpenForms[0]; Console.WriteLine(form.Text); //--- プロパティの編集 form.BackColor = Color.LightPink; //--- private変数の参照 Console.WriteLine(form.xMas); //--- ComboBoxを動的に追加 //var comboBox = targetApp.Type<ComboBox>()(); //comboBox.Items.Add("xin9le"); //comboBox.Items.Add("ナオキ"); //comboBox.Items.Add("緑のタイツ"); //form.Controls.Add(comboBox); //--- 追加したComboBoxから値を取得 //Console.WriteLine(comboBox.SelectedItem); //--- dllインジェクション //WindowsAppExpander.LoadAssembly(targetApp, Assembly.GetExecutingAssembly()); //targetApp.Type(typeof(Program)).ShowMessageBox(); //--- 相手プロセス上で以下に定義したメソッドを呼び出す Console.ReadKey(); //--- 終了 process.CloseMainWindow(); process.WaitForExit(); } } } |
ビルドして実行。TestAppからSampleAppのプロパティにアクセスしたり、メソッドを呼び出すことができた。そういう風にして外部アプリからターゲットアプリを操作して自動テストを行う仕組みらしい。
商用ツールにはテストケースをUIを使って定義できるものがあるが数十万円のコストがかかる。それに対して、Friendlyはテストケースをコーディングする手間がかかるけどオープンソースなので無料で使える。役立つシーンはありそうだ。
新規テンプレートアップロード時に以下のメッセージが表示されるとき。
ファイルのサイズが大きすぎます。有効な最大サイズは2 MiBです。
html/.htaccess
1 |
php_value upload_max_filesize 5M |
ECCUBEでアップロードできない。upload_max_filesizeを設定する場所 | エス技研
https://blog.s-giken.net/183.html
1 2 3 4 5 6 7 |
$ cd /var/www/html/phpMyAdmin/ $ cp -ipr config.sample.inc.php config.inc.php $ vi config.inc.php $cfg['Servers'][$i]['host'] = '<MySQLサーバー>'; $ sudo service httpd restart |
MySQL : phpMyAdminの接続先を変更 | DN-Web64
http://www.dn-web64.com/archives/web/phpmyadmin_setting/
kakakikikekeのブログ: phpMyAdminで接続先のDBを変更する方法
https://kakakikikeke.blogspot.com/2012/11/phpmyadmindb.html
バックグラウンドで実行中のnodeをkillしても勝手に生き返ってしまう。
なんでだーと思ったらPM2というNode.jsスクリプトをデーモン化するツールが使われていましたとさ。
node.js node.jsスクリプトをpm2でデーモン化する -でじうぃき
http://onlineconsultant.jp/pukiwiki/?node.js%20node.js%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%82%92pm2%E3%81%A7%E3%83%87%E3%83%BC%E3%83%A2%E3%83%B3%E5%8C%96%E3%81%99%E3%82%8B
以下のような状況。
1 2 |
$ sudo npm run dev sudo: npm: command not found |
sudoのパスが通っていない。カレントユーザのパスを継承したければ以下のように設定する。
1 2 3 |
$ sudo visudo #Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" Defaults env_keep +="PATH" |
sudo「コマンドが見つかりません」PATHが初期化されているときの対処法 – シングスブログ
https://blog.thingslabo.com/archives/000395.html
何故かcommand not found が出るときの対処法 – cha-shu.log
http://cha-shu00.hatenablog.com/entry/2017/03/02/123659
1 2 3 |
#!/bin/sh filename=`date +%y%m%d-%H%M%S` mysqldump -uhomestead -psecret zone > $filename.sql |
MySQLのバックアップ関連で最低限やるべき項目
https://qiita.com/yu_0105/items/528d627c35412c92c2ef
date コマンド | コマンドの使い方(Linux) | hydroculのメモ
https://hydrocul.github.io/wiki/commands/date.html