やる気パルスが回復するアニソン

40代のおっさんなので、新しいのは知りません。リンクは歌詞。

機動戦士ガンダム0083-STARDUST MEMORY-

THE WINNER
THE WINNER

銀河鉄道999

THE GALAXY EXPRESS 999
THE GALAXY EXPRESS 999

キン肉マン II世

愛のマッスル
愛のマッスル

真(チェンジ!!)ゲッターロボ 世界最後の日

今がその時だ
今がその時だ

六神合体ゴットマーズ

愛の金字塔
愛の金字塔


う。面倒になってきた。アニソンのリスト作るサービスくらいあってもよさそうなんだが…。

ご自宅で作るSelenium4を使ったクロスブラウザテスト環境

Selenium4を使って自宅のPC(WindowsMac)でクロスブラウザテスト環境を作ったのでまとめ

Seleniumとは?

Web ブラウザの操作を自動化するためのフレームワークWebサイトによると、大きく3つの機能?がある。

  • Selenium WebDriver
    • ブラウザの操作をプログラムで制御できる
  • Selenium IDE
    • ブラウザの操作を記録、再生できる
  • Selenium Grid
    • ブラウザの操作をリモートの端末に対して並行実行できる

今回は、Selenium WebDriver(PHP)とSelenium Gridを使ってクロスブラウザテスト環境を構築した。 具体的には以下のOS/ブラウザの組み合わせのテストができる環境を構築した。

  • Selenium WebDriverを使って実行された命令を、Hubが受け取り、対象となるNodeに対して実際の実行を命令する。
  • Appiumはモバイルアプリの操作を自動化するフレームワーク。今回スマフォを使うので導入してみた。
    • AppiumとSelenium Hubとの接続は、Selenium Nodeを経由して行う。(SeleniumのRelayという機能を使っている)
  • iPhoneMacにUSBで接続、Pixel4は無線で接続している。
  • iPhoneを操作するためにMac側にAppiumを入れたので、Pixel4もMacに接続した。

利用したアプリケーションのバージョン

環境構築方法

Windows

以下をダウンロードして、同じディレクトリに置く。

Mac

Android Studioをインストールする

Safariの自動操作を可能にする

デフォルトの設定ではSafariの自動操作はできない。以下を参考に自動操作をできるようにする。

Appiumをインストールする

AppiumのServerの項を参考にインストールする (Node.jsのインストールが事前に必要)。

SeleniumとWebDriverをダウンロードする

以下をダウンロードして、同じディレクトリに置く。

  • Selenium4
    • 2022/11/23時点では4.6.0
  • ChromeDriver
    • ChromeのバージョンによってダウンロードするDriverが異なるので注意

Gridを立ち上げる

事前準備

Macとスマフォ(iPhoneとPixel4)を接続する

以下を参考にAndroidを接続する。adp pairでペアリングをしてから、‘adb connect`で接続をすればOK。

iPhoneはUSBで接続する(ワイヤレスデバッグができるかどうかは試したことがない)。

Gridを立ち上げる

WindowsでHubを起動した後、WindowsMacそれぞれでNodeを立ち上げHubに接続する。

Windowsのみ】Selenium Hubを起動する

Seleniumを保存したフォルダで以下のコマンドを実行する。

java -jar selenium-server-<バージョン>.jar hub --host <PCのIPアドレス>

WSL2を使っている場合、PCにIPアドレスが複数割り当てられているはずなので、--hostMacからアクセスできるIPアドレスを指定する。 起動したら以下のようなログが表示される。太字のURLはNodeを起動する際に必要なものなのでメモなどしておく。

07:47:20.853 INFO [UnboundZmqEventBus.] - Sockets created
07:47:21.863 INFO [UnboundZmqEventBus.] - Event bus ready
07:47:22.358 INFO [Hub.execute] - Started Selenium Hub x.x.x (revision yyyyyy): http://zzz.zzz.zzz.zzz:4444

Selenium Nodeを起動する

WindowsMacそれぞれでNodeを立ち上げる。

Windows

事前準備の項でダウンロードしたJARやWebDriverを保存しているフォルダで、以下のコマンドを実行する。 Seleniumが利用できるWebDriverを見つけてくれるからドライバを指定をする必要がない。便利。

java -jar selenium-server-<バージョン>.jar node --hub <HubのURL>

パラメータ調整したい場合は以下を参考に。

Mac

Appiumを起動する

Appiumの設定ファイルを用意する。ファイル名は適当でよい。

{
    "capabilities": [
        {
            "platform": "MAC",
            "browserName": "safari",
            "language": "ja",
            "maxInstances": 1
        },
        {
            "platform": "IOS",
            "deviceName": "iPhone X",
            "browserName": "safari",
            "language": "ja",
            "maxInstances": 1
        },
        {
            "platform": "Android",
            "deviceName": "Pixel 4",
            "browserName": "chrome",
            "language": "ja",
            "platform": "Android",
            "maxInstances": 1
        }
    ],
    "configuration":
    {
        "cleanUpCycle":2000,
        "timeout":30000,
        "maxSession": 1
    }
}

chromedriverのあるフォルダで以下のコマンドを実行する。

ANDROID_HOME=<Android SDKのパス> appium --chromedriver-executable ./chromedriver --nodeconfig <設定ファイルのパス>

Android SDKのパスは /Users/<ユーザ名>/Library/Android/sdk になるハズ。

Selenium Nodeを起動する

Relayの設定は多くなるので設定ファイルにする。ファイル名は適当でよい。 configsにはAppiumの設定ファイルで指定したcapabilitiesと同じ内容を記載する。

[node]
detect-drivers = false

[relay]
url = "http://localhost:4723/wd/hub"
status-endpoint= "/status"
configs = [
  "2", "{\"browserName\": \"chrome\", \"platformName\": \"Android\"}",
  "2", "{\"browserName\": \"safari\", \"platformName\": \"IOS\"}",
  "2", "{\"browserName\": \"safari\", \"platformName\": \"MAC\"}"
]

以下のコマンドを実行する。

java -jar ../selenium-server-4.4.0.jar node --hub http://192.168.0.5:4444 --config <作成した設定ファイルのパス>

動作確認

<HubのURL>/ui 例(http://192.168.0.5:4444/ui)に接続すると、現在の状況が分かる。

12は同時実行可能なセッションの数。大きすぎる気もするが自分で使うだけなのでまぁよしとする。

ブラウザを操作する

PHPを使ってWindows/Mac/iPhone/Pixelの4つのデバイスでブラウザを開いてみる。

事前準備

PHPとComposerをインストールする。 (頑張って…)

実行する

以下のコードを保存する。

<?php

require __DIR__ . '/vendor/autoload.php';

use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\WebDriverBrowserType;
use Facebook\WebDriver\Remote\WebDriverCapabilityType;
use Facebook\WebDriver\WebDriverPlatform;

$serverUrl = 'http://192.168.0.5:4444';

$browserAndPlatforms = [
    "Windows - Edge" => [
        WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::MICROSOFT_EDGE,
        WebDriverCapabilityType::PLATFORM => WebDriverPlatform::WINDOWS,
    ],
    "Windows - Chrome" => [
        WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::CHROME,
        WebDriverCapabilityType::PLATFORM => WebDriverPlatform::WINDOWS,
    ],
    "Mac - Safari" => [
        WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::SAFARI,
        WebDriverCapabilityType::PLATFORM => WebDriverPlatform::MAC,
        "appium:automationName" => "Safari", // safaridriverを使うのに必要だった気がする?
    ],
    "Android - Chrome" => [
        WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::CHROME,
        WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANDROID,
    ],
    "iPhone - Safari" => [
        WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::SAFARI,
        WebDriverCapabilityType::PLATFORM => "IOS", // 定義されてない
        "appium:automationName" => "Safari",
        "appium:nativeWebTap" => "true",
        "appium:bundleId" => "com.apple.mobilesafari",
    ],
];

foreach ($browserAndPlatforms as $name => $desiredCapabilities) {
    print("WE ARE NOW RUSHING INTO ${name}\n");

    $driver = RemoteWebDriver::create(
        $serverUrl,
        $desiredCapabilities
    );
    
    $driver->get('https://www.google.com');

    sleep(3);
    
    $driver->quit();
}

プログラムを保存したフォルダで、以下のコマンドを実行する。WebDriverがインストールされる。

composer require php-webdriver/webdriver

同じくプログラムを保存したフォルダで、以下のコマンドを実行する。「ブラウザを起動、Googleのトップページにアクセス、数秒後にブラウザが閉じる」がデバイスごと繰り返されるはず。

php ./<保存したファイル名>

ゲーム(Satisfactory)で改善の練習をしてみる

アドベントカレンダーのネタにするためにゲームを使って改善の練習をしたのでまとめ。

対象のゲーム

現在ハマっているSatisfactoryというオープンワールドの一人称視点工場建設ゲーム。

以下、Satisfactoryについて箇条書きで紹介(文章にできなかった)。

  • プレイヤーは、とある惑星に派遣された主人公となり、採掘した鉱石を加工しアイテムや設備を整え、惑星を開拓するのが目的
  • 設定されたマイルストーン(クエストのようなもの)をクリアすることで、採掘できる鉱石や、加工できるアイテム、設備が増える
  • マイルストーンはいくつかのティアに分かれており、アンロックするためには指定されたアイテムを納品する必要がある
  • 現時点でティアは8段階まで。最終段階のアイテムを作るためにはめっちゃ沢山の鉱石、アイテムが必要で、生産ラインも超複雑になる
  • この生産ラインを作るところがハマりポイントで、Youtubeでは様々な動画が上がっている
  • 詳しいことはSatisfactory日本語 Wikiを見るのが良い
  • 作成会社はヤギシミュレーターで有名なCoffee Stain Studios
  • ゲームは2019年に早期アクセス版としてリリースされ、今(2022/11/20)でも早期アクセス版のまま開発が進んでいる
  • Windows版はSteam:Satisfactoryで購入することができる。値段は3180円。たまにセールで安くなることがあるのでそれを待ってみるのもいいかも

改善のお手本

改善と聞くと原田 騎郎(Harada Kiro)氏の顔が思い浮かぶのは私だけではないはずだ。原田氏の資料を探したところ、改善の3つの顔 | Attractor Incが見つかった。
この資料によると、改善には以下の3つの流れがあるらしい。これに沿って現状を改善してみることにする。

  • 漏れを止める
  • 流れをよどみなく
  • 新しい流れをつくる

やったこと

結論から言うと、最初の「漏れを止める」で時間切れとなった。ので、その部分のみ記載する。

漏れを止める

この「漏れを止める」とはどういうことか? 資料の8ページには以下のようにある。

  • 流れが価値を生んでいるかを確かめる
    • スピードを落とす / 止まる
    • プロセスがどう動いているかを観察する
    • 必要ならプロセスを足す
    • 効果に注目する
    • 効率は気にしない

資料に従って1つずつ確認していくことにする。

流れが価値を生んでいるかを確かめる

流れはコンベアや鉄道作ったラインそのものだと思うが、価値はどうだろうか?
そもそも価値って何だっけ?

われわれが生活していくうえでの必要や欲望を満たし、われわれに満足を与えるものは、いずれも価値あるものとされる 価値とは - コトバンク

ということで、Satisfactoryにおける必要や欲望を満たし、私に満足を与えるものということで考えてみる。ここまではTier7, 8の解除が欲望だった。これからは何が欲望になるだろうか?

  • 欲望1「Tier7, 8のマイルストーンを解除してやれることを増やしたい」
    • 順当な目標。Tier8では核を使った発電もできるようになるらしい。スゴイ
  • 欲望2「天空に鉄道網を作りたい」
    • Tier7、Tier8の達成に必ずしも必要というわけではないんだけどやってみたい。ロマンである

価値を決めたので次のステップに行くことにする。

スピードを落とす/止まる

Satisfactoryで遊ぶのを一旦やめて、この改善のことだけ考えることにしたのでやれてるハズ。

プロセスがどう動いているかを観察する

生産ライン、電力、移動/搬送の3つの観点で現状について考えてみる。

生産ライン

メインの生産ラインは「Tier7, 8を解放する」という目標を達成するために作られている。具体的には以下のアイテムを作るための生産ラインとなっている。

作成したアイテムは倉庫に入れているがすでに満杯状態(多いものだと数千個レベルで溜まっている)であり、多くの設備は停止している状態。

メインの生産ラインは最初に降り立ったエリアに作成している。生産ラインは作成時期によってまちまち。最初のころに作ったラインは平屋、練習を兼ねて複数階層になっているところもある。必要なアイテムの多くは現地で素材を加工して搬送しているが、近場に素材があるものはその場で加工をしているものもある。現地で加工したアイテムはコンベアを使ってエリアに送り込んでいるのだが、その時その時に必要なものをコンベアを建て増して運び込んだので整理がされているとは言いづらい。

新しいエリアの探索や、鉄道敷設のために必要なアイテムはラインに設置している設備から抜き取ったり、倉庫から取り出したりしている。あちこちに散らばってるため必要なものを集めるために走り回る必要がある。また、目標達成に必要のないアイテムは現地で加工のみしておりメインのエリアに搬送していないため、アイテムが必要になるたびに現地に取りにいかないといけない。

電力

石炭発電機と、燃料式発電機を利用している。総発電量は4821MW。
全設備の電力使用量は4500MWだが、実際に使っているのは1800MW。(停止している設備があるから)
石炭発電に使っている石炭をアイテムの製造に使いたいのだが、電力が不足するのが怖くて発電を止められてない。

移動/搬送

主にハイパーチューブを使っている。が、新しいエリアは面倒なのでまだハイパーチューブを敷設していないため、徒歩がメインとなっている。アイテムの搬送は主にコンベア。新しいエリアで鉄道を使い始めたところ。

観察した結果

電力や移動/搬送にも課題はあるが、生産ラインに一番ストレスを感じているようだ。とりあえず観察はしたから次のステップに進んでみる。

必要ならプロセスを足す

特に必要を感じなかったのでスルー。

効果に注目する/効率は気にしない

効果とは。

ある働きかけによって現れる、望ましい結果。ききめ。しるし。 効果(こうか)の意味 - goo国語辞書

価値=欲望を実現するにあたり、必要なアイテムが作れているか=効果として考えてみる。効果を「必要なアイテムが作れているか」とした場合、現在の欲望は大きすぎる(ほぼ全てのアイテムを作る必要があるため)ため、細分化することにした。

  • 欲望1「Tier7, 8のマイルストーンを解除してやれることを増やしたい」
  • 欲望2「天空に鉄道網を作りたい」
  • 鉄道網に必要な土台/鉄道/電線/コンベア/ハイパーチューブを敷設できるようにしたい

細分化した欲望を実現するにあたり必要なものが生産できていれば効果が出ているということにして、現状を分析してみよう。 観点は、先ほどの生産ライン、電力、移動/搬送の3つとする。

電力、移動/搬送

電力は足りているし、移動/搬送もそれほど困ってないのでスルー。

生産ライン

何がどれだけ必要なのか正確に把握していないので、そこを明らかにするところから始める。作りたい設備を洗い出し必要なアイテムをリストアップすればいいのだが、冒頭にも書いたように生産できるアイテムがめっちゃ多いため非常に面倒。自分でデータを整備するのはやりたくない…。Redditなど海外の情報も含めていくつか探した結果、以下の方法で整理することにした。

  • 生産に必要なアイテムを割り出すためのデータとしてgreeny/SatisfactoryToolsを利用する
    • お世話になっているSatisfactory Toolsのサイトで利用されているデータ
    • データはUpdate5のもの(現在はUpdate6)なのでちょっと古いが、他はもっと古かったのでそこは我慢
    • 形式はjsonで、GitHubでメンテナンスされているから、加工が楽
  • Excelを使って建設物に必要なアイテムを列挙する表を作成、必要なアイテムを割り出す
    • 最初はプログラムを書くつもりだったのだが、面倒になったのでExcelでできないか模索
    • PowerQueryを使ってJSONのデータを表に変形、作成した表を使って必要なアイテムを割り出す

作りたい設備から割り出したアイテムは全部で21種類。★マーク以外はなんらかの形で製造をしていることが分かった。

  • ★AI Limiter
  • ★Alclad Aluminum Sheet
  • Cable
  • Computer
  • Concrete
  • Copper Sheet
  • Encased Industrial Beam
  • Heavy Modular Frame
  • Iron Plate
  • Iron Rod
  • Modular Frame
  • Motor
  • Plastic
  • Portable Miner
  • Quickwire
  • Reinforced Iron Plate
  • Rotor
  • Rubber
  • Steel Beam
  • Steel Pipe
  • Wire

足りないアイテムは工場を作れば良いが、以下の問題が残っている。アイテムの収集のために走り回るのをやめたい。

新しいエリアの探索や、鉄道敷設のために必要なアイテムはラインに設置している設備から抜き取ったり、倉庫から取り出したりしている。あちこちに散らばってるため必要なものを集めるために走り回る必要がある。また、目標達成に必要のないアイテムは現地で加工のみしておりメインのエリアに搬送していないため、アイテムが必要になるたびに現地に取りにいかないといけない。

価値を更新した。

  • 欲望1「Tier7, 8のマイルストーンを解除してやれることを増やしたい」
  • 欲望2「天空に鉄道網を作りたい」
  • 鉄道網に必要な土台/鉄道/電線/コンベア/ハイパーチューブを敷設できるようにしたい
    • 敷設に必要なアイテムを製造し、あとから取り出しやすくなるよう収納しておきたい

ようやく改善

ここまでのステップを踏むことで、目的とやることが決まった。

  • 目的:原子力発電所に必要なアイテムが作れる、鉄道網に必要な土台/鉄道/電線/コンベア/ハイパーチューブが敷設できる
  • やること:目的を達成するために必要なアイテムを生産するラインの準備と、取り出しやすい収納方法の検討

生産ライン、収納方法については、Youtubeで見つけた以下の方法を真似することにした。

www.youtube.com

生産ライン

循環するコンベアに必要なアイテムを流し、中に作った設備に引き込む方法。アイテムの種類が増えてもコンベアを増やす必要がなく、設備の増設もしやすい。

収納方法

1本のコンベアに収納したいアイテムを流し、アイテムを選別するSmart Splitterという装置を使って倉庫に流し込むという方法。アイテムが増えてもコンベアを増やす必要がなく、アイテムが増えてもコンベアを延長、倉庫を追加し、Smart Splitterで流し込めばよいだけなので拡張性にも優れている。

やることが決まってしまえば作業はこれまでやったことの積み重ね。完成までにそれほど時間はかからなかった。

改善結果

結果、今後必要なアイテムが作りやすい生産ラインと、作ったアイテムを取り出しやすい収納ができあがった。効率でいうとまだまだだが、改善結果としては大満足である。

まとめ

現在ハマっているSatisfactoryというゲームで原田 騎郎(Harada Kiro)氏の改善の3つの顔 | Attractor Incを参考に改善活動を行った。

今回の「漏れを止める」の活動期間は20日程度。結構長い。最初はゲーム止めて大丈夫かなぁ(モチベが下がって再開しなくなるかも)と不安もあったが、結果からみると「さらにハマる」ための準備作業になったようなので何よりである。とはいえ、必要なアイテムを洗い出す作業はなかなか上手く行かず、投げ出しそうになった。Excel + Power Queryを使って上手く洗い出しができたからいいものの、そうでなかったらどうなっていたことやら…。(Power Queryは仕事で使っていたので作業自体は特に苦労することもなかった。どこで何が役に立つか分からないものだなぁ…)

改善前は沢山のやれることに気が散ってしまい迷走気味だったので、この活動で「シンプルではっきりしたやること」(必要なアイテムを生産するラインの準備と、取り出しやすい収納方法の検討)を見つけられたのがとても良かった。今後ゲームで迷走しそうになったら立ち止まって考えてみる…かもしれない。

最後に。Satisfactoryはやればやるほど味がでるスルメのようなゲーム。改善活動の練習にもぴったりだということも今回の記事でお判りいただけたと思う。興味が出たという方はぜひ遊んでみてほしい。
store.steampowered.com

私がCucumber/Gherkinが好きな理由

おススメ記事は過去のものが沢山あるし、そもそもおススメするのが苦手なので、自分が好きな理由を書いてみる。

Cucumber/Gherkinって何?

BDD Testing & Collaboration Tools for Teams | Cucumber

テストツールの1つ。
Behavior-Driven Development (BDD)で利用されることが多い…ハズ。あんまり話聞かなくなった気もする。

以下のような感じで、テストを自然言語で書くことができる。

    # ログインとお知らせの確認
    もし    受講者 ユーザ "nobiinu" パスワード "fugafuga" でログインする
    ならば  "nobiinu様" と表示されていること
      かつ  視聴可能な単元に以下が表示されていること:
        | コース     | 単元   | 視聴期限 |
        | コース1 | 第5回 | 11月14日 |
        | コース1 | 第6回 | 11月14日 |

もちろん、自然言語だけでは実行はできない。
自然言語を実際のアクションに落とし込むためのコードを書く必要がある。グルーコード(glue code)と呼ばれているようだ。
以下は、コードの例。

    /**
      * @When 受講者 ユーザ :user_name パスワード :user_password でログインする
      */
    public function 受講者_ユーザ_パスワード_でログインする($user_name, $user_password)
    {
        $this->visitPath('/');
        $this->getSession()->getPage()->fillField("user", $user_name);
        $this->getSession()->getPage()->fillField("password", $user_password);
        $this->pressButton("ログインする");
        $this->getSession()->wait(10000, "document.readyState === 'complete'");
    }

Cucumberがテストシナリオ?に記述した文章に対応するコードを見つけ出して実行する。

    もし    受講者 ユーザ "nobiinu" パスワード "fugafuga" でログインする

に対応するコードとして

    /**
      * @When 受講者 ユーザ :user_name パスワード :user_password でログインする
      */
    public function 受講者_ユーザ_パスワード_でログインする($user_name, $user_password)

の関数を見つけ出して実行する。仕組み、設定などはここでは割愛。

なんで好きなの?

3つ書いてみる。1つ目はそもそものお話。3つ目は副作用。2つ目がCucumber/Gherkinだからこその話になるかな?

  • テストをコードで書ける
  • 日本語でテストが書ける
  • 日本語を使うことで、なんとなく頭の中の整理が進む (気がする)

それぞれを説明してみる。

テストをコードで書ける

これに尽きる。MPは集中力、根気と変換していただいて問題ない。
手動でのテストは根気が続かないのである。仕事だろ? と言われても、続かないので仕方がない。
だからと言って、コードであれば集中力が持続するのかというと、そうでもない。テストを手動でやるよりはマシというお話。
そんなところで開き直っても仕方はないものの…。

日本語でテストが書ける

コードならスラスラ書けるのかというとそうでもない。
私はオブジェクト指向が苦手である。どうやら責任を分解するのが苦手らしい。なんでも1つのクラスにやらせちゃう。なんでも一人でやろうとする自分に似ている気がする。

業務の言葉に該当する英語を考えるのも苦手である。苦手というか、時間をとって調べるという手間を書けるのを惜しんで、コードを書いてしまう。
この年になってようやくわかったんだけど、すぐ動かしたいという衝動を抑制するのが下手らしい。
なんにせよ、コードを書くために必要な手間を惜しむせいで、あとから見て、なんだこりゃ? なコードになる。自業自得ではあるが寂しいものだ。

そんな私でも、日本語で書けるなら、多少はマシなものができる。日本語であれば「あれ」は「あれ」とそのまま書けばいいのだ。
お客さんが話している言葉、自分も適切だと思う言葉でテストを表現することができる。素晴らしい。

日本語を使うことで、なんとなく頭の中の整理が進む (気がする)

そうやって日本語を使ってテストを書いていると、なんとなく違うな? こっちの方が分かりやすい表現だな? とか気づくことがある。
気づいたら、ちょっと文章を直してみる、いい感じになると悦に入ることができる。そうでなければ元に戻せば良い。
自分なりに理解が進む。進んだ理解に合わせて、表現を変えることができる。

テストが成長していく様を体験できる。嬉しい。楽しい。

ツラみについて

もちろん嬉しいことばかりではない。他のテストコードと同じようにメンテがツラい。

Cucumber/Gherkinを使う場合、日本語で書いたテストシナリオと、プログラム言語で書いたグルーコードの2つが必要になる。 両方をメンテナンスしなければいけない。

テストシナリオが変わってなくても、画面が変われば、テストコードを変える必要がある。
大きくUIを見直す時はため息がでる。

テストシナリオで使っている表現を修正しようとしたら、すべてのテストシナリオの修正と、テストコードの修正が必要だ。
作りすぎていると修正に苦労する。

画面の操作には Selenium を使っているので、クラスやIDなどを使って対象の要素が見つけやすくなるようにしておいた方がいい。
新しいプロダクトであれば、最初からそういう方針で画面を作っていけばいいのだけれど、既存のプロダクトはそうはいかない。
レガシーなプロダクトで使うのであれば、相応の覚悟が必要になる。

Cucumberのせいではないが、Selenium使うのもまぁまぁツラい。以前動いていたコードが、ブラウザ、ライブラリのバージョンアップによって動かなくなることがある。あのブラウザでは動いたコードが、このブラウザでは動かないといった問題とも付き合わなければならない。

何が言いたかったの?

メンテのこと考えるとうんざりするところはあるけれど「自分的に納得できる日本語で書いたテストがコマンド一発で実行できる」というご褒美があるので続いているというお話だったらしい。好きなところを書くつもりだったんだけども…。

ちなみに、現在は、コマンド入力してエンターキーを押すだけで、以下のデバイスを使ったテストを全自動で実行できる。ウヒヒヒヒ。

3Dプリンタではまった「真っすぐ」の沼について

3Dプリンタで表札を作ろうとしている、デザインは字+ちょっとしたイラストなので、そんな難しくはない。
が、10月くらいから手を付け始めてまだ終わってない。「真っすぐ」の沼にはまっているからだ。

なので、タイトルは正確に言えば「はまった」ではなく「はまり中」になのだけど、そろそろ諦めようかと思ってるので、「はまった」でも問題はない。多分。

3Dプリンタを使った表札づくり

3Dプリンタで表札を作るには、以下の工程が必要になる。

  • 3Dモデルで表札を作る
  • 作った3Dモデルを3Dプリンタで印刷する

3Dモデルで表札を作る

アプリを使って、表札を作る。私はフリーのソフト Blender.jp を使っている。理由は特にない。強いて上げるなら、ハトマスクをBlenderで作った から?
四角形を並べるだけなのであまり困ることはないが、注意点が2つほど。

日本語を入力するときはコピペ

Blenderは日本語を直接入力することができない。ので、メモ帳とかに入力した文字をコピペする。
参考: Blender 2.9のテキストオブジェクトで日本語フォントを利用する - MRが楽しい

イラストはSVGで取り込む

描いたイラストをBlenderに取り込むには、SVGというフォーマットに変換するといいらしい。
参考: 【Blender】イラレで描いた図形を立体化する - おもちゃラボ

FireAlpacaというペイントツールを使って描いた線画を、PNGとして保存。保存したファイルを、SVGに変換する。今回は、PNG to SVG というオンラインのサービスを使ってみた。(素性はわからないので利用するときはお気をつけて)

左がFireAlpacaで描いたイラスト。これをSVGに変換して、Blenderに取り込んだ後、厚みをつけると右になる。

f:id:couger:20211127170250p:plainf:id:couger:20211127171747p:plain

作った3Dモデルを3Dプリンタで印刷する

Blenderで作った3Dモデルを、スライサーというソフトを使って3Dプリンタが扱うデータに変換する。
私が使っているELEGOO Mars 2 は、CHITUBOXというスライサーがおススメされているのでそちらを使う。

参考: 【初心者向け】CHITUBOXの設定・使い方 / Anycubic Photon・MARS・Phrozen / 光造形用スライサー | SHIGEMON PRESS -3Dプリンター版-

スライサーで作ったデータを、USBメモリにコピーして、3Dプリンタで印刷すればできあがり…のはずなんだけども、ここからが沼。

「真っすぐ」の沼

イラストにそこそこ手間がかかったが、モデルを作ること自体は簡単だ。印刷も長くて2~3時間くらい待てば終わる。
だが「真っすぐ」は簡単に終わらない。
以下は失敗作の山。プラバンで作った方が早いし、安いんではないかと思う。が、3Dプリンタはロマンなのでいいのだ。

f:id:couger:20211127192451j:plain

それはさておき、「真っすぐ」の敵は大きく分けて「反り」と「太り?」の2種類がある。 太り? と書いてあるのは、みんなが言ってる肉太り、太りが私のそれと合ってるのか良く分からないから。

反り

反りは印刷後に起きる。薄い板上のものほど反りやすい…気がする。表札ではないが、反りがよくわかる写真が以下。

f:id:couger:20211016190207p:plain

太り?

以下の写真でいうと、四角形の底辺が丸く曲線を描いている。これが(私の言うところの)太り。

f:id:couger:20211127180928j:plain

対策

今の自分の知識では「多少は気にしない」「印刷後に修正する」が解決策になりそう。それじゃあまりにも何なので緩和策について書いてみる。

緩和策

反りについては「プラットフォームに対して垂直水平に配置しない」が有効そうだ。太りについては対策が分かっていない。

プラットフォームに対して垂直水平に配置しない

理屈は理解できてないんだけども、確かに反りが減る。私は x,y,z軸にそれぞれ10度程度傾けて印刷している。
光造形の3Dプリンタは高さによって印刷時間が決まる。反り対策として印刷物を傾斜させると通常よりも高さが出る=印刷時間が伸びる。もちろん、幅も取るので一度に印刷できる個数が減る。痛しかゆし。とはいえ、大きく反るよりはマシ。

f:id:couger:20211127181837p:plain

参考: SK本舗ユーザーのリレーコラム#05「3Dプリンターで水洗いレジンを使用した際の反り対策と模型制作を考える」(今井誠) – SK本舗-3Dプリンターとレジンの通販・購入

番外:印刷の成功率を上げるために

記事を書くために探してたら、印刷の成功率を上げるためのあれこれがまとまっているサイトがあったので、備忘録がてら。
最初に読めばよかった…orz (と思いつつも、絶対最初に読まないタイプだから諦める)

3Dプリンタを使って半年たったので分かったことをまとめてみる

4月に3Dプリンタを購入。半年くらい使ってみたので、現状の構成や分かったことをまとめてみる。

きっかけ

フルアーマーガンダムMk-IIのアーマーを自作したかったんだけど、不器用なのでプラバンやパテで作るのは無理。というか、心が折れる
3Dプリンタなら、設計図ができればいくらでも量産ができるのではないか?! という超安易な考えで購入。もちろん、そんな簡単にいくはずはなく現在も四苦八苦している最中。

作ったもの

フルアーマーガンダムMk-IIのアーマー。写真の灰色のパーツがそれになる。
スタイルはお察しだけど、3Dプリンタのおかげで精度は非常に高く(少なくとも私が自作するよりは…)、量産も可能。3Dプリンタ、スゴい。

構成

3Dプリンタ以外はあれこれ試して今の構成に落ち着いている。

3Dプリンタ

ELEGOO Mars 2 にした。今のところ不具合もなく問題なく使えている。

当時のログを見ると以下のブログを見て購入を判断したようだ。先人に感謝。

レジン

臭いの少ないプラントベースのレジンを使っている。他のレジンを使っていた時は家族から臭いといわれていたんだけど、このレジンに変えてからはほぼなくなった。
500mlと1Lがあるが、1Lの方が圧倒的にコスパが良いということを最近知ったので、今後は1Lを買う予定。

エタノール

今使っているレジンはアルコールで洗浄する必要がある。イソプロピルアルコールは取り扱いが大変らしいので、消毒用のエタノールを使っている。最初は無水でやってたけど、無水でなくてもよさそう。水で洗浄できるレジンもあるのだが、前述した臭いの問題で使えない。

コスパを考えて、以下を買ったのだが、値段にあんまり差がないようだ…。 ちなみにイソプロピルアルコールの取り扱いの難しさについては以下のブログで知った。
はじめての3Dプリンター!造形準備と後片付けについて - やなか技術士事務所のホームページ

モデリングツール

Blender。フリーのモデリングツールで、以前使ったことがあったのでそのまま使っている。
blender.org - Home of the Blender project - Free and Open 3D Creation Software

スライサーソフト

chitubox。みんなが使っている。確か3Dプリンタのマニュアルがこれだった気も…。
All-in-one SLA/DLP/LCD Slicer-HOME

運用や工夫、課題について

印刷

反り対策には角度が有効

プラットフォームに対して垂直ではなく、傾きを持たせた方が反りが少なくなるという記事を読んで試してみたのが以下。プラットフォームと並行、垂直に印刷した手前(裏面梁なし)と真ん中(梁あり)は反りがかなり出ているが、プラットフォームに対して角度をつけて印刷した奥のもの(梁あり)は反りがほぼない。
今は、X、Y、Z軸に対して15~20度くらい傾けて印刷するようにしている。

参考:SK本舗ユーザーのリレーコラム#05「3Dプリンターで水洗いレジンを使用した際の反り対策と模型制作を考える」(今井誠) – SK本舗-3Dプリンターとレジンの通販・購入

自動で付くサポートに頼りすぎない

スライサーソフトにはサポートを自動で付ける機能が付いている。とっても便利。なんだけど、万能ではない。(そりゃそうだ)

具体的にいうと上記のようなパーツにサポートを自動でつけると以下(反時計回りに90度回して、真下から見ている図)のようになる。

そのまま印刷したら、丸で囲んでいる部分、角のところが欠けて印刷されてしまった。
なので、最近は自動のサポートに加えて、危なそうなところ、角のところや辺の中央などにサポートを追加するようにしている。

参考: SK本舗ユーザーのリレーコラム#04「SLAプリンタの剥離抵抗と、より高精細な造形をするためのヒント」(IKE) – SK本舗-3Dプリンターとレジンの通販・購入

洗浄

2段階の洗浄でアルコールの入れ替え頻度を下げ たい

以下のように2段階で洗浄している。できるだけアルコールの入れ替え頻度を下げたいという欲求から。

  • プラットフォームについたままの印刷物に、スプレーを使ってアルコールを吹き付け、表面のレジンを大まかに流す
  • タッパーに入れたアルコールに、印刷物を漬け込んで、刷毛で細かいレジンを流し落とす

5,6回くらい使いまわしているけれど、洗浄後の印刷物がべた付く感じはない。ので欲求は満たせている気がするのだが…。
使っているタッパーは以下のもの。深すぎたかと思ったんだけど、ちょうどいい感じ。

ちなみに刷毛はこちら。

後処理?

サポート材は手で除去できる

手で除去できることを知るまで、1本1本、ニッパーで切っていた。超面倒かった…。
40%くらいの密度(Density)でサポートを生やすと、除去しやすくなるので良いのだが、前述するように必要な個所にサポートがないと、望んだ形にならないのでそこは注意。後、力余って印刷物を割ってしまうこともあるので、力加減にも注意。

課題

洗浄後、サポートが付いている面がネトネトする → 二次硬化までやろう!

上記の方法で洗浄すると、サポートのない面はツルツル、キレイなのだが、サポートが付いている面は若干ネトネトしている。レジンが落としきれてないのか、硬化が甘いのか。理由はわからない。

レジンが落としきれていないということであれば、超音波洗浄機を使えばいいんだろうけども…。

二次硬化してないせいだった。二次硬化するとべたつきが消える。水洗い可能なレジンの場合はハンドソープで洗うのが良いらしい。

その他

3Dプリンタ置き場

アルコールやレジンで床が傷むといやなので、ブルーシートを敷いている。

今まで印刷したパーツ達

なんかの記録になるかなーと思い集めている。全部で227グラムあった。使ったレジンは1~1.5Lくらい。

Behat + Minkで作ったテストをAndroid+Chromeでも動くようにした

状況

  • PHPで作ったアプリのE2EテストをBehat+Minkで実装している
  • アプリがモバイルでも動くかどうか確認する必要が出てきた
  • Behat+Minkで作ったE2Eテストを、Android上のChromeを使って動かして、動作確認をしたい

大まかな仕組み

以下のようになる。 すでにMacbook上でChrome Driverを使ってE2Eテストを動かしているので、adb -> Android -> Chromeのところを準備すればOK。

Behat -> Mink -> Selenium -> Chrome Driver -> adb -> Android -> Chrome

動かすためにやったこと

  • AndroidWifi経由で操作できるようにする
  • behat.ymlにAndroid用のプロファイルを追加
  • Androidからアクセスできるよう、BeforeScenarioでMinkとアプリの設定を切り替え
  • Chromeでのみ発生する要素をクリックできない問題に対処

以下、それぞれの説明

AndroidWifi経由で操作できるようにする

Android 11以降は、Wifi経由で操作ができるようになる。それ以前だとUSB接続のみ。
USBは面倒なのでWifiで接続できるようにした。

Android Debug Bridge(adb)  |  Android デベロッパー  |  Android Developers

ハマった点

  • Android Studioを最新にアップデートする
    • 苦労した覚えはあるんだけどなんだったか忘れた
  • ADBの接続コマンド
    • 公式ドキュメントを見てやれば大丈夫

behat.ymlにAndroid用のプロファイルを追加

extra_capabilitiesにgoog:chromeOptionsのandroidPackageを入れるのがポイント。 base_urlについては後述。

android:
  extensions:
    Behat\MinkExtension:
      base_url: http://#localhostIP#:8090
      selenium2:
        browser: chrome
        capabilities:
          extra_capabilities:
            goog:chromeOptions:
              androidPackage: com.android.chrome

Androidからアクセスできるよう、BeforeScenarioでアプリの設定を切り替え

通常、Macbook上ではlocalhostを使って接続しているので、URLは常に http://localhost で良いのであるが、AndroidからWifi経由で接続する場合は、IPアドレスを使って接続する必要がある。で、MacbookIPアドレスは常に変わる。(固定しろよって話もあるが...)

ちょっと面倒だけど、毎回実行時にIPアドレスを取得して、Minkとアプリの設定を書き換えることにした。

RawMinkContextを継承しているクラスで以下のコードを、@BeforeScenario で実行すればOK。

        $baseUrl = $this->getMinkParameter('base_url');

        if (strpos($baseUrl, "#localhostIP#") > 0) {
            // IPアドレスを取得
            $ipAddressesRC = preg_grep("/^192\./", gethostbynamel(gethostname()));
            $ipAdderss = array_shift($ipAddressesRC);

            // URLを書き換え
            $newBaseUrl = str_replace("#localhostIP#", $ipAdderss, $baseUrl);

            // 全てのContextに設定を反映
            $environment = $scope->getEnvironment();
            foreach ($environment->getContexts() as $context) {
                if ($context instanceof \Behat\MinkExtension\Context\RawMinkContext) {
                    $context->setMinkParameter('base_url', $newBaseUrl);
                }
            }
        }

ポイントは $environment = $scope->getEnvironment(); 以降のコード。
利用している全てのContextに対して、設定を変更する必要がある。

上記で変更したURLを使って、アプリの設定を書き換えればOK。コードは省略。

Chromeでのみ発生する要素をクリックできない問題に対処

ここまでで実行するだけならできる...んだけど、テストが通るようにするために、Chrome特有の問題に対応する必要があった。

問題とは以下のもの。画面外にある要素をクリックしようとするとエラーになる。

seleniumにてButtonがクリックできない時の対処法 - Qiita

解決方法は難しくない。Clickの前に上記のエントリにあるようにスクロールをするか、フォーカスしてあげればOK。
カスタムのContextを使っている場合は、コードにスクロールなり、フォーカスするコードを追加すればよい。

私は、カスタムのContextに加えて、Behat\MinkExtension\Context\MinkContext も使っていたので、メソッドをオーバーライドしてフォーカスするコードを追加した。以下のような感じ。クラスの名前がやっつけすぎるな...。

class MyMinkContext extends MinkContext implements TranslatableContext
{
    public function clickLink($link)
    {
        $link = $this->fixStepArgument($link);
        $elem = $this->getSession()->getPage()->findLink($link);
        $elem->focus();
        $elem->click();
    }