OmniAICreator/Qiita-1.07M huggingface dataset:
Jenkins生みの親、川口さんが立ち上げたLaunchableのWebinarを聞いてきた

もうすでにご存じの方も多いと思いますが、Jenkins開発者の川口さんは、現在[Jenkins関連のサービスを展開しているCloudbees](https://www.cloudbees.com/)の[一線を退き、新たなスタートアップであるLaunchableを立ち上げ](https://kohsuke.hatenadiary.com/entry/hello-launchable)ておられます。

今日（日本時間8月7日 午前2時）に、そのWebinarがあったので、聞いてみました。

## そもそもLaunchable は何を売っているのか
もともとの川口さんのBlogなどでは、機械学習とテストを組み合わせた事業を行う、ということのみが語られていましたが、その後の詳細については、実はすでにPublickeyでの既報があります。

- [ソフトウェアテストの実行を機械学習で効率化する。Jenkins作者の川口氏が立ち上げた「Launchable」で実現しようとしていることとは](https://www.publickey1.jp/blog/20/jenkinslaunchable.html)

機械学習xテスト で思いつきやすいのが、テストの生成やメンテナンスそのものを（半）自動化してくれるようなソリューションです。例えば[Autify](https://autify.com/ja)なんかは、テストのメンテナンスを機械学習を通じて行うことがキーのソリューションです。

Launchable が行っているのは、それとはちょっと方向性が違います。先程のPublickeyから引用すると、以下のような感じです。

> いま取り組んでいる製品というのは、開発者がコードに加えた変更に敏感なテストを探し当てて割り当てる、というものです。するとテストを全部走らせなくても、10分の1程度のテストを走らせるだけで十分なフィードバックをテストから得られるようにする、ということをやっています。

上記のコンセプトはWebinarからも同一に思えました。ただ、コンセプトや実際の運用イメージなどが語られていたので、そのあたりを共有しようと思います。

## Launchableのキーメトリクス: TTFF（Time to First Failure)の最小化
TTFFというのは、「最初にテストが失敗するまでの時間」です。ちょっと違和感がある表現だと思いますが、**テストで価値を生んでいるのは失敗するテスト**です。失敗してフィードバックが発生するからこそ、書いているテストに価値があります。常に成功するテストは、実は何も生み出しておらず、むしろそのテストにかかる時間が無駄ですらあるのです。

例えば、全体のテストを回すのに8時間かかる、みたいな状況になっているとしましょう。8時間のテストはコード変更のたびに実行するのは不可能ですから、よくある話としては夜間ビルドに回すことになります。

ということは、最悪の場合、朝に埋め込んだ欠陥がテストで判明するのは翌日の朝、みたいなことになります。
この場合プロセスにおけるTTFFは、12時間を超えてきます。

Lanchable はここに手を入れます。つまり、少量でも欠陥を抽出しやすいテストを全テストケースの中から選び出し、それを実行するのです。例えば、8時間（480分）のテストのうち、5%の実行で欠陥検出率が50%となるようなテストケースを機械学習により選び出せるとしましょう（ここがLaunchableのエンジンです！）。

5％ということは24分です。24分なら、30分ごとにテストを回すことができます。欠陥検出率は50%なので、TTFFの期待値は1時間となり、開発者は圧倒的に早いフィードバックを得ることができます。

## Launchable の仕組み
もちろん詳細なアルゴリズムは企業秘密ですから明かしてもらえませんでしたが、モデルとして利用しているデータについては少し言及がありました。
面白いのは、**ソースコードそのものの解析はしていない**、というところです。解析しているのは、

- だれが、どのファイルを、どのくらい、変更したかの情報（≒ チェンジセット）
    - Gitのコミット情報以上のことは収集しないそうです
- そのコミットの時点でテストを実行した場合、どのテストが失敗するか（= 欠陥を検出し機能するか）

という情報です。おそらく前者がインプット、後者が教師データとして機械学習に利用されるのでしょう（他にもあるとは思いますが）

ソースコードそのものを解析しないので、このモデル自体はプログラミング言語に依存しないものとなります。なのでLaunchableは幅広いプロジェクトに対して、適用可能性がある、ということを示唆しています。（もちろん、言語によって異なる事前学習モデルを用意するなどはあるような気はしますが）

## どうやってLaunchable を使うのか
Lauchableは、テストに対するエージェントのように機能します。Lauchableに与えるのはGitのチェンジセット範囲（コミットレンジを指定したり、PRのマージコミットを指定したりするのでしょう）で、Launchableはそれを受けて実行すべきテストケースのリストを返してくれます。そのリストを見て、テストランナーが選択的にテストを実行する、という形です。

たしかにこの仕組なら、言語やテストフレームワークに依存せず、その外側から仕組を構築することができそうです。

## で、どうやったら使えるの？
まだまだ初期フェーズなので、現状はコンサル的にプロジェクト分析を行ってもらい、プロジェクトごとの機械学習モデルを作成し、という風にテーラーメイドで適用する形になっているそうです。SaaS的な適用も将来的には行われるのでしょうが、まだそういった利用しやすいケースは直近ではなさそうです。

とはいえすでに大規模な自動テスト実行に疲弊している方は、一度コンタクト取る価値はあるのではないでしょうか！
【Python】pip10以降の新しい書き方を覚えておこう

`pip list`みたいにpipコマンドをそのまま使うと、以下の警告が表示されてドキッとする。この書き方は古いようだ。

```
WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
```

## 単独のpipを使用するのは非推奨

以下のようにPython付属のpipを使用する事を推奨している。

```shell
$ python3 -m pip [pipコマンド]
```

Python付属のpipを使用することで何が変わるわけではないが、僕的によく使うpipコマンドのスニペットを貼っていこうと思う。


## pipでインストール済みのパッケージをリストアップする場合

```shell
$ python3 -m pip list
```

## pipでパッケージをインストールする場合

```shell
$ python3 -m pip install [パッケージ名]
```

## pipでバージョン指定してインストールする場合

```shell
$ python3 -m pip install [パッケージ名]==指定バージョン
```

### 例)バージョン3.4でopencv-pythonをインストールする場合

```shell
$ python3 -m pip install opencv-python==3.4
```
ただし、3.4というバージョンは存在しないので、ご丁寧に指定できるバージョンを教えてくれる。

```
ERROR: Could not find a version that satisfies the requirement 
opencv-python==3.4.10.35 (from versions: 
3.2.0.6, 3.2.0.7, 3.2.0.8, 3.3.0.9, 3.3.0.10, 3.3.1.11, 
3.4.0.12, 3.4.0.13, 3.4.0.14, 3.4.1.15, 3.4.2.16, 3.4.2.17, 
3.4.3.18, 3.4.4.19, 3.4.6.27, 3.4.7.28, 4.0.1.24, 4.1.0.25, 4.1.1.26)
```
ERROR: No matching distribution found for opencv-python==3.4

とてもありがたい。

## 既にインストール済みのパッケージのバージョンをダウングレードする場合

```shell
$ python3 -m pip install [パッケージ名]==指定バージョン
```
新規インストールと同様にinstallをそのまま実行してもらえれば良い。

```
Installing collected packages: opencv-python
  Attempting uninstall: opencv-python
    Found existing installation: opencv-python 4.1.1.26
    Uninstalling opencv-python-4.1.1.26:
      Successfully uninstalled opencv-python-4.1.1.26
Successfully installed opencv-python-3.4.7.28
```

このようにインストールされていたものは自動的にアンインストールされる。

## 最後に

基本的に「**$ python3 -m pip**」を覚えておけば問題ない。
Pythonにpipが付属するのがバージョン3.4以降だということには注意が必要。

## 関連記事

- [【Python】macOSでpipを使えるようにする](https://qiita.com/ohbashunsuke/items/e7c673db606a6dced8a6)


## 環境

- Python 3.5.3
- pip 20.2.1
【Mac】ローカルホストに、一時的に外部からアクセス出来るようにする

## ngrokアカウント作成
https://ngrok.com/

## Setup&Installation
### ngrokをダウンロード
<img width="1178" alt="スクリーンショット 2020-08-07 3.10.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125006/b50a9116-442e-0a67-5e2c-bba3df6f9447.png">

### 1. Unzip to install
ダブルクリックで解凍してから、二本指クリック（control+クリック）から「開く」を選択
or

```shell:Macターミナル
unzip /path/to/ngrok.zip
```

### 2. Connect your account
アカウントに接続

```shell:Macターミナル
./ngrok authtoken {Your Authtoken}
```
AuthenticationタブのYour Authtokenでも確認出来る

### 3. Fire it up
ローカルに外部から接続出来るhttpとhttpsのURLを発行

```shell:Macターミナル
# Dockerとかで80番ポートを使用している場合(http://localhostに繋ぎたい場合)
./ngrok http 80

# MAMPで8888番ポートを使用してる場合（http://localhost:8888に繋ぎたい場合）
./ngrok http 8888
```
```shell:結果
Forwarding    http://xxxxxxxxxxxx.ngrok.io -> http://localhost:80                        
Forwarding    https://xxxxxxxxxxxx.ngrok.io -> http://localhost:80                   
```

`http://xxxxxxxxxxxx.ngrok.io`
or
`https://xxxxxxxxxxxx.ngrok.io`
にアクセスするとローカルホストに接続される
PythonのDiscord Webhookで超お手軽にローカル画像を投稿する

#要点
discordwebhook使って `file={ "attachment": f }` で指定するのがミソ

#事前準備
・`pip install discordwebhook` しとく
・Discordのサーバー設定→IntegrationsでWebhookを作っておく

#コード

```postLocalImageToDiscord.py
#! /usr/bin/env python
# coding: UTF-8

from discordwebhook import Discord
import sys

if __name__ == '__main__':
    #第一引数に画像パスを指定する
    args = sys.argv
    if 2 <= len(args):
        image_path = args[1]
        discord_webhook_url = "ここにWebHookのURL"

        discord = Discord(url=discord_webhook_url)
        with open(image_path, 'rb') as f:
            discord.post(content="画像投稿テスト", file={ "attachment": f })
    else:
        print('引数が不足しています 第一引数に画像パスを指定してください')
```

#実行結果
`python postLocalImageToDiscord.py "C:/Users/username/Downloads/floweroflife.gif"` コマンドの実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181210/13e02689-190a-1a8d-f9c0-7e434389b5e1.png)
Ubuntu20.04でOneDriveを使う


## 手順

### 依存パッケージインストール
```
sudo apt install libcurl4-openssl-dev
sudo apt install libsqlite3-dev
sudo snap install --classic dmd && sudo snap install --classic dub
```

### OneDriveインストール

```
git clone https://github.com/skilion/onedrive.git
cd onedrive
make
sudo make install
```

### 起動

```
onedrive
```
ログインURLが表示されるので、そのURLへアクセスし、ログイン後のURLを貼り付けるとホームディレクトリの下に`OneDrive`フォルダが作成される


### 自動起動設定

```
systemctl --user enable onedrive
systemctl --user start onedrive
```


## 参考
https://github.com/skilion/onedrive
https://tobubiyori.blogspot.com/2017/11/ubuntulinuxonedrive.html
ubuntu18.04にEPSONエコタンクモデルのプリンタドライバを入れる

サスティナブルが重視される時代だけど、やはり紙を超えるディスプレイデバイスはない。きっと、どんなにディスプレイ技術が進化しても、可読性、保存性、一覧性、直感的検索性、見やすさ、災害に対する強さ、保存にも読むときにもエネルギーを使わないという紙の特徴を備えたものは出てこないと思う。正直、老眼が進んできたのでディスプレイより紙が読みやすいというのもある。
ということで、Linux(ubuntu 18.04)でも印刷は必須なので、EPSONプリンタドライバをインストールして印刷できるようにする。

## ドライバー入手

EPSONの公式サイトに[Linux用ドライバーについて記載がある](https://www.epson.jp/support/taiou/os/linux_se.htm)ので一読。
[Linuxドライバーダウンロード可能機種一覧](https://www.epson.jp/support/taiou/os/linux_selist.htm)に記載のあるプリンターはドライバーがダウンロードできると書いてある。しかし、我が家のプリンタEW-M630TBは一覧に載っていない…
しかし、ダメ元で[ダウンロードサイト](http://download.ebz.epson.net/dsc/search/01/search/?LG2=JA&OSC=LX)で検索してみると、一覧にはなかったが、ドライバーがヒットした。つまり、一覧になくてもドライバーが入手できることがあるようなので、諦めずに検索するほうが良いようだ。
![Screenshot from 2020-08-04 00-02-51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641874/40293cd4-4677-3c50-e44d-9a06f12938a1.png)
まずESC/P-R Driver 2(generic driver)のダウンロードをクリック。
ubuntu 18.04 AMD64 desktopを使っているので、
epson-inkjet-printer-escpr2_1.1.15-1lsb3.2_amd64.deb
をダウンロード。
続いて、EPSON Printer Utilityをダウンロード
epson-printer-utility_1.1.1-1lsb3.2_amd64.deb
複合機なので、スキャナドライバー（All-in-one package）もダウンロード。
まず、マニュアルをダウンロード
imagescanv3_man_j.pdf
[パッケージダウンロードページ](http://support.epson.net/linux/ja/imagescanv3.php)へ飛ばされるので、
Ubuntu 18.04 LTS 64bit(amd64)のdownloadボタンをクリック。
imagescan-bundle-ubuntu-18.04-3.63.0.x64.deb.tar.gz


## インストール(プリンター)

EPSONのドライバーダウンロード時の表の下に小さく注意書きされていたLSBをapt-getで入れる

```command:端末
$ sudo apt-get install lsb
```

ダウンロードした.debファイルは、~/ダウンロードにはいっているので、ファイルからたどってダブルクリック→[インストール]、ドライバー（epson-inkjet-printer-escpr2_1.1.15-1lsb3.2_amd64.deb）、ユーティリティ（epson-printer-utility_1.1.1-1lsb3.2_amd64.deb）の順にインストールした。

tar.gzファイルの解凍

```command:端末
$ tar -zxvf imagescan-bundle-ubuntu-18.04-3.63.0.x64.deb.tar.gz
$ cd tar -zxvf imagescan-bundle-ubuntu-18.04-3.63.0.x64.deb
$ sudo ./install.sh
(再起動)
$ sudo shutdwon -r now
```

設定→デバイス→プリンターを開いて、ジョブの受付不可となっているプリンターが出ていたので、削除。しばらくすると復活するが、設定できないので無視。
[追加のプリンター設定]→[追加]→[ネットワークプリンター]→[EPSON EW-M630T(xxx.xxx.xxx.xxx)]を選択。
テストページを印刷して、ubuntuと書かれた色鮮やかなページが印刷されたら完了！
![Screenshot from 2020-08-04 00-59-29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641874/1610f696-6893-2455-f9c6-7284187f9325.png)
npm run でコマンドが実行できない[Windows Docker]

# 環境

- Windows10
- Docker Toolbox

```
$ docker -v
Docker version 18.09.0, build 4d60db472b
```

# やりたいこと

```powershell
$ docker-compose run --rm /bin/bash
```

```bash
$ npm i --no-bin-links
$ npm run eslint
```

みたいなコマンドを使いたい。

# エラー

```
sh: 1: eslint: not found
```

こんな感じで怒られる。

# 原因

`node_modules/.bin` にコマンドのリンクが置かれていないため。
Mac では自動で作成されていたため、[Windows ではシンボリックリンクがはれない問題](https://qiita.com/Y-Kanoh/items/58815aafb7346930f370) が原因なのかもしれない。

# 解決法

node_modules を一度全て削除し、docker を介さずに `npm i` を実行すると `node_modules/.bin` が作成される。

```powershell
> npm i
> docker-compose run app --rm /bin/bash
```

```bash
$ npm run eslint
```

とおった。

# 解決法2

[DockerでVolumeをマウントするとき一部を除外する方法](https://qiita.com/suin/items/e53eee56da23d476addc) を使って、シンボリックリンクが張られる箇所、`node_modules`とのマウントから除外する。

- docker-compose.yml の一部

```yml
version: "3.7"
services:
  app:
    ...
    volumes:
      - {作業ディレクトリ}/node_modules
```

docker-compose を修正した後、

```bash
$ docker-compose run app /bin/bash
# npm i
# npm run eslint
```

# おまけ

http://minatooe.hatenablog.jp/entry/2017/12/15/234418

> あとは、Win は管理者権限なら symlink を作れるようになるらしいので、vagrant を動かすコマンドプロンプトを管理者権限で起動すると--no-bin-links をつけなくても大丈夫になるらしい。

とあったのでやってみたができなかった…。
シェルスクリプト用のベンチマークツールを作りました

## はじめに

シェルスクリプトで実装したコードの実行速度の比較を行いたかったのですが手ごろなツールが見つからなかったので、シェルスクリプト用のベンチマークツールとして「[ShellBench](https://github.com/shellspec/shellbench)」を作りました。POSIX シェル準拠で作っているので bash 以外にも対応しています。可能な限り正確に測定できるように設計しており、どの書き方が速いのか？やどのシェルが速いのか？を調べることができます。

計測結果はこのような形で出力されます。（数字は1秒間に実行できた回数）

```
------------------------------------------------------------------------------------------------
name                                   sh       bash        ksh       mksh       posh        zsh
------------------------------------------------------------------------------------------------
output.sh: echo                   279,335    121,104    375,175    179,903    201,718     59,138
output.sh: printf                 277,989    118,461    209,123        180        179     63,644
output.sh: print                    error      error    281,775    182,388      error     63,006
------------------------------------------------------------------------------------------------
```

ちなみに同様のツールとして ksh-community から [shbench](https://github.com/ksh-community/shbench) がリリースされています。こちらは ksh の他 bash、zsh、mksh に対応しているようですが、配列などの拡張命令を使用しているのですべての POSIX シェルで動くわけではありません。

## 課題だった点

一般的にベンチマークツールは比較的簡単に作れる部類のソフトになると思いますが、シェルスクリプト特有の制限のため一筋縄ではいきませんでした。

### 小数点以下の時間の取得方法が限られる

POSIXシェル準拠の範囲で小数点以下の時間を取得方法には `times` コマンドと `time` コマンドがあります。しかし `times` コマンドはユーザー CPU 時間やシステム CPU 時間を知ることはできますが、実時間が取得できません。また `time` コマンドは計測したいコードを外部コマンドとして実行しなければいけないため、特定のシェルスクリプトコード（例えば `echo` と `printf` の比較等）のベンチマークを取りたい場合には適していません。（数秒かかるような処理の計測であれば十分使えるのですが）

### 外部コマンドの呼び出しに時間がかかる

現在の時刻を取得するために `date` コマンドなどの外部コマンドを使う方法が考えられます。しかし外部コマンドの呼び出しは時間がかかる重い処理なのでミリ秒レベルで取得したい場合は誤差が大きくなってしまいます。

bash 5 以降 または zsh であればシェル特殊変数 `EPOCHREALTIME` からマイクロ秒単位で現在の時刻を出力できるのですが、残念ながらその他のシェルでは使えません。

### `test` コマンド実行のコストが大きい

ミリ秒、マイクロ秒単位の短い時間で終わる処理のベンチマークを取る場合、一回実行するだけでは処理時間が小さすぎるためある程度の回数ループすることになりますが、ループ回数の比較に使うであろう `test` (`[ ]`) コマンドはシェルビルトインであっても遅いです。そのためベンチマーク対象のコードによっては、ほとんどがループ処理のベンチマークになってしまう可能性があります。

## 実装について

計測方法はコードの実行に何秒かかったか？ではなく1秒の間に何回実行できたかをカウントしています。（一定の秒数計測して1秒単位になおしています。）

計測のための本質的なコードは以下のようなコードです。


```sh
while __count=$(($__count+1)); do
echo "test" # 計測対象のコード
done
```

実際には以下のような簡単なDSLから変換しています。

```sh

#bench "echo"
@begin
echo "test"
@end
```

ベンチマーク対象コード以外は、ループと加算処理しか行なっていないためループ処理にかかるコストは可能な限り小さくなります。停止条件のない無限ループとなっていますが、別プロセスから一定の秒数後にベンチマーク実行プロセスを `kill` することでループを停止させています。

### 補正モード

さらに厳密に測定結果を求めるための補正モードがあります。補正モードでは最初に空ループを測定し、ベンチマークの計測結果から空ループ分を差し引く形に計算することでより正確な値になるように補正を行っています。
Skyline Problem　の解決方法

# The Skyline Problem by using an iterative method
1. sorts the elements of a given array in ascending order.
2. Set the initial value of sum to 0.
3. Then use iterative methods：
     **_3.1 Find the smallest value array[0] in the array Because it has to be painted at least array[0] times.
        3.2 now sum += array[0]
        3.3 Set a new empty array
        3.4 Then, starting with the second element array[1] and ending with the last　element array[len(array)] in the array, insert the difference between these　values and the first element into the new empty array.
       3.5 Update the array： clear the array and assign the value of new array to 
         original array
       3.6 Back to step 3.1 until the length of the array is 2_**
 
4. if the length of array is 2, sum += array[0] + difNum  (difNum = array[1] - array[0])
5. return the sum

#Code 
```php
def solution(A):
  # sorts the listA in a ascending order
  newA = sorted(A)
  return solution_help(newA)



def solution_help(array):
  # Set the initial value of sum to 0
  sum = 0
  if len(array) == 1:
    sum = array[0]
    return sum
  while len(array) > 2:
    min = array[0]
    sum += array[0]
    arraynew = []
    for i in range(1,len(array)):
      difNum = array[i] - array[0]
      arraynew.append(difNum)
    array = []
    array = arraynew
   
  if len(array) == 2:
    difNum = array[1] - array[0]
    sum += array[0] + difNum
  return sum
 
list1 = [1,3,6,4,5,1,1,1] 

print(solution(list1))  
#6
```
macOS Catalinaに自然言語処理フレームワークAllenNLPの環境構築


# 本記事のゴール
普段、言語処理まわりのモデルをPyTorchで構築することが多いのですが、もっと楽にコードを書くためにAllenNLPを使ってみることにしました。
本記事では、[公式ページ](http://docs.allennlp.org/master/)に従って、自然言語処理フレームワークAllenNLPの環境構築を行います。

# 環境
- macOS Catalina (Version 10.15.5)

# 手順

## 仮想環境の構築
Condaをベースに環境構築します。

```bash
$ conda create -n allennlp python=3.7
$ source activate allennlp
```

## インストール
`jsonnet`のエラーが吐かれたので、まずはじめに `jsonnet`をインストールします。
参考：https://stackoverflow.com/questions/56141193/cant-install-allennlp-with-pip-on-mac

```bash
$ conda install -c conda-forge jsonnet
$ pip install allennlp
```

## 確認
`allennlp`コマンドが使えるか確認します。

```bash
 allennlp
2020-08-07 01:14:18,807 - INFO - transformers.file_utils - PyTorch version 1.5.1 available.
usage: allennlp [-h] [--version]  ...

Run AllenNLP

optional arguments:
  -h, --help     show this help message and exit
  --version      show program's version number and exit

Commands:

    evaluate     Evaluate the specified model + dataset.
    find-lr      Find a learning rate range.
    predict      Use a trained model to make predictions.
    print-results
                 Print results from allennlp serialization directories to the
                 console.
    test-install
                 Test AllenNLP installation.
    train        Train a model.
```

# さいごに
`jsonnet`のエラーで少しハマりましたが、無事インストールまで完了しました。
次はチュートリアルを見ながらモデル構築まで行いたいです。

# 参考ページ
- [AllenNLPで簡単にDeepな自然言語処理](https://qiita.com/itok_msi/items/d788155848be46e5407e)
- [MacOS MojaveでAllenNLPのインストールを失敗した話](https://qiita.com/tomoharr24/items/c0bfaf39e23483a569d5)
OutSystemsでPublishしたら自動テストを走らせる

開発によってビルドが壊れたのを、ビルド毎の自動テスト実行で検出するというのをOutSystemsでもやりたい。

# 概要
単体テストの実行にはBDDFrameworkを利用する。
テストは、専用のテストモジュールに作る。

処理の流れは以下の通り。

1. テスト対象モジュールをPublishしたときにモジュール内のTimerが起動する
2. Timerは別モジュールにあるリグレッションテスト用Actionを、テストモジュールを指定して起動する
3. リグレッションテストActionの処理は以下の通り
    1. CI/CD Probe (Forge) のREST APIでテスト画面のリストを取得
    2. テスト画面のリストを順番に実行していく。これには、BDDFrameworkのRunTestSuiteが使える
    3. テストのいずれかが失敗したら、開発チームに通知する。通知方法はいくつか考えられる

ここに出てくるBDDFrameworkやCI/CD ProbeというForgeモジュールについては、以前別の記事を書いたのでそちらを参照。
[OutSystemsで回帰テストを外部から実行する](https://qiita.com/jyunji_watanabe/items/45526c3bc9646320adb8)

# Publishでテストを起動する
これには、テスト対象モジュール内にTimerを作ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/91d02707-af04-a3af-7c48-cbb9cc74fc2f.png)

Scheduleプロパティを「When Published」にするのがポイント。
これは、文字通り、Service Studioで1 Click Publishしたたときに自動で起動することを示します。

なお、TimerのSchedulerは環境毎にService Centerで変更可能です。
が、ScheduleなしでPublishしておいて、Service Centerで「When Published」にしても、Publish毎に起動するようにはなりませんでした。
本番環境で動いてしまうことを避けるため、本当ならScheduleはデフォルト無しにしておきたいのですが、しかたない。

Timerは次のステップで作成する共通部品のServer Actionを呼び出すだけ。

# 共通部品（リグレッションテストを実行するServer Action）
リグレッションテストは、ほぼ全ての開発モジュールで作成することになります。
そこで、同じ実装があちこちに飛び散ってしまうことを避けるため、Server Action (Service Actionでも構いません) 共通部品に作りましょう。

作成例：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/d40c766b-1628-363b-3e76-9150988df2ec.png)


## テストスイートの抽出
CI/CD Probe (Forge部品) にある、ScanBDDTestEndpointsというREST APIで取得します。
パラメータにアプリケーション名を指定すると、そのテストスイートだけを抽出できます（作成例のTestApplicationNameを使う）。

また、リグレッションテストを高速に実行するため、処理時間のかかるテストを特定のUI Flowに集めておいて対象外にする（作成例のWebFlowExcudePatternを利用）。このため、テスト作成のルールで、処理時間のかかる処理を特定のサフィックスなどをつけたUI Flowに分離するようにしましょう。

それに対して、アプリケーションには複数のモジュールが含まれるので、余計なテストを実行しないように、ListFilterを使って対象のテストモジュールだけを抽出しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/c0a8f38e-049f-2f51-347a-745cc3f2251b.png)

## テストの実行
BDDFrameworkのREST API RunTestSuiteに抽出したテストスイート情報を渡して実行。
[以前書いた記事を参照](https://qiita.com/jyunji_watanabe/items/45526c3bc9646320adb8#bddframework%E3%81%AE%E3%83%86%E3%82%B9%E3%83%88%E3%82%B9%E3%82%A4%E3%83%BC%E3%83%88%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B)

# テストの失敗を通知する
開発で新たに作り込んだバグは一刻も早く開発者に知らせたいので、知らせる処理を検討します。

## 候補
- Process：OutSystemsだけで完結する。開発者に「失敗したテストの詳細を確認する」ワークフローを割り当てる
- メール：メールサーバーが必要
- ビジネスチャット：Slackなどを使っていて、開発者が全員参加しているなら、そこに通知する

Processは、割当方法が
- 全ユーザー
- ユーザーID（Timerは実行時に、Publishしたユーザーを取得できない）
- Role (コンパイル時に選択するため、動的に選べない）

なので、開発者に通知するには使いにくい。
そこで、モジュール毎に通知先をEntityで管理しておき、メールかビジネスチャットに通知するのが現実的。

最近はメールをあまり注視していないので、個人的には、Slackがいいかな。Forgeにコネクタがあるし（未検証）。
複数のAWSアカウントの切り替え方法

## はじめに
環境ごとに複数のAWSアカウントを利用することがあるのですが毎回アカウントIDを忘れてしまうので対応のメモです。

## 結論
以下のようにブックマークに保存すれば毎度IDが入力された状態で呼び出されます。

```
https://{{awsアカウントID}}.signin.aws.amazon.com/console
```
{{awsアカウントID}}の部分にアカウントID（12桁）を入力するようにしてください。
ブックマークでAWSアカウントの環境とか明示してあげるとわかりやすいです！

※　アクセスした結果のリダイレクトされたURLをブックマークしないように注意
私はこれをしてて毎回、前回のサインインしていたアカウントのIDが出てきてました。。

## 終わりに
大したことない内容ですが、個人的にハマってたので誰かの役に立てたら嬉しいです！
JuliaでHelloWorld!

今後需要が増えていくであろうJuliaを勉強し始めたのでHello Worldの文だけとりあえず載せておきます。

インストールはできている前提です。インストールに関して知りたい方はつよつよエンジニアが書いている記事がたくさん出回っているのでそちらをご覧ください。

#Hello World!

```julia:hello.jl
println("Hello World!")
```

拡張子はjlです。

記述方法が非常にシンプルで初心者でも理解しやすいなといった印象です。

ちなみにVScodeでコードを書き始めたのですが、拡張機能でJuliaパッケージをインストールしないと動作しないので注意が必要です。

以上です。
また勉強の内容をQiitaに上げていこうと思います。よろしくお願いします。
Flutter flutter_date_pickers 日本語化

FlutterのDateTime Pickerと言えば `showDatePicker`でカレンダーのダイアログが立ち上がるのがよく使われていますが、今回はダイアログでなく、画面にDatePickerを埋め込みたかったのでこちらを使用せず [flutter_date_pickers](https://pub.dev/packages/flutter_date_pickers)を使用しました。

こちらUIに合わせて色なども変更でき、

- DayPicker 
- WeekPicker 
- RangePicker 
- MonthPicker 

と4種類あり、実装も簡単で使いやすかったです。

ただ、pub.devみても日本語化する方法が全く載っていなくて、調べても出てきませんでしたが、このプラグインのGitHubリポジトリーのissueに載ってました。

[Support for localization](https://github.com/MariaMelnik/flutter_date_pickers/issues/6)

こちらに書いてある様に `flutter_localizations.dart` をimportして、 `main.dart`に以下を追加して日本語の設定を行います。

```
import 'package:flutter_localizations/flutter_localizations.dart';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      supportedLocales: const [
        Locale('en'),
        Locale('ja'),
      ],
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
    );
  }
}
```
しかし、この設定してビルドしたら以下のエラーが発生！

```
Unsupported operation: Cannot set value in unmodifiable Map
```
こちらのエラーに対しては、[[Flutter] Unsupported operation: Cannot set value in unmodifiable Map の対処方法](https://qiita.com/welchi/items/99f7041a3e1f54a06c15) に書かれてある通りに `initializeDateFormatting()`が原因でした。
```
 Intl.defaultLocale = 'ja_JP';
await initializeDateFormatting('ja_JP');
```
こちらをコメントアウトするとちゃんとビルドできました！
<img width="697" alt="スクリーンショット 2020-08-07 0.06.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100644/5c0efaf8-f5e0-f8ff-a686-3f01d8762900.png">
この通り、年月日が日本語になりました。
material.dart の DateTime Pickerでなくても画面に埋め込みができ使い方によってはTimePickerと合わせて1画面で使うことが可能です。

### 参考文献
- [[Flutter] Unsupported operation: Cannot set value in unmodifiable Map の対処方法](https://qiita.com/welchi/items/99f7041a3e1f54a06c15) 
- [Support for localization](https://github.com/MariaMelnik/flutter_date_pickers/issues/6)
- [flutter_date_pickers](https://pub.dev/packages/flutter_date_pickers)
jest-puppeteerでパスワード付きProxyを越える

`jest-puppeteer.config.json` のブラウザ起動オプションにProxyのアドレスを設定する。

```js:jest-puppeteer.config.json
module.exports = {
  launch: {
    args: [
      '--proxy-server=your.proxy.domain:port',
    ]
  }
}
```

一見、 `--proxy-server` オプションにユーザー名もパスも含めて `user:pass@domain:port` のように指定すれば良さそうに思えるが、これは上手く動作しない。
コード上で認証情報を設定する必要がある。

今回は `custom-environment.js` に設定する例を記す。

```js:custom-environment.js
const PuppeteerEnvironment = require('jest-environment-puppeteer');

class CustomEnvironment extends PuppeteerEnvironment {
  async setup() {
    await super.setup();

    const page = this.context.page;
    // authenticateメソッドで認証を行う
    // ユーザー名、パスワードは環境変数から取るようにしたほうが良いだろう
    await page.authenticate({
      username: process.env.PROXY_USER,
      password: process.env.PROXY_PASS
    });
  }
}

module.exports = CustomEnvironment;
```

余談だが、ブラウザの起動オプションは他にも色々指定することが出来、オプションは[コチラ](https://peter.sh/experiments/chromium-command-line-switches/)にリストアップされているようだ。
他にも幾つかProxyに関するオプションがあるので参考にすると良い。
連想配列のデフォルト値を省略すると実行速度は速くなる

#気になったこと

以下のように引数の連想配列に不足しているキーを自動で補ってくれる関数がある。

```f.php
 function f($option = []) {
    $option += [
        'text1' => '1',
        'text2' => '2',
        'separator' => '/',
    ];
    return implode($option['separator'], [$option['text1'], $option['text2']]);
 }
```

関数の呼び出し時に(a)オプション配列にすべてのキーを指定する場合、(b)デフォルト値を省略した場合、どちらの実行速度が速いか？

#時間計測スクリプト

```benchmark.php
 $t1 = microtime(true);
 for($i=0;$i<500000;$i++) {
    f([
        'text1' => 'abc',
        'text2' => 'def',
        'separator' => '/',
    ]);
 }
 $t2 = microtime(true);

 $t3 = microtime(true);
 for($i=0;$i<500000;$i++) {
    f([
        'text1' => 'abc',
        'text2' => 'def',
    ]);
 }
 $t4 = microtime(true);
 
 echo ($t2-$t1) . "\n";
 echo ($t4-$t3) . "\n";
 exit;
```

# 結果
| 条件       |       実行時間avg (sec) | 
|:-----------------|------------------:|
| (a)オプション配列にすべてのキーを指定する場合 | 0.12881302833557 |
| (b)デフォルト値を省略した場合 | 0.12693285942078 |

* デフォルト値を省略したほうが実行速度は（若干）速い。
* フレームワーク(CakePHP, Laravelなど)の関数のように中身が複雑だと、さらに差が広がる。
* デフォルト値は省略したほうが実行速度は速いが、フレームワークのバージョンアップでデフォルト値が変わり、デグレが起きる可能性に留意する。
PowerShellを使ってMinecraftのリソースを正式名でエクスポートする

# 最初に
Minecraftはデフォルトリソースをハッシュ名にして保存しています。実際のリソース名とはJSONファイルを使用して関連付けています。

```json
{"objects": 
    {
        "resource1.png": 
            {"hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "size": 1234},
        "resource2.png": 
            {"hash": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "size": 5678}
    }
}
```

このような形でハッシュとリソース名を対応付けています。これをリソース名にしてエクスポートしようという試みです。

# 対応環境
Minecraft 1.16とPowerShell 5.1で実行できることを確認しました。また、オープンソース版のPowerShellでも実行できると思われます。

**最低限の検証しかしていません。**

# 実際のコード
```powershell
$objects_dir = "C:\Users\Owner\AppData\Roaming\.minecraft\assets\objects"; # .minecraftフォルダ内のassets/objectsまでのフルパス
$listjson = "C:\Users\Owner\AppData\Roaming\.minecraft\assets\indexes\1.16.json" # .minecraftフォルダ内のassets/indexes内の任意のバージョン名のJSONファイルまでのフルパス

$exportdir = "C:\Users\Owner\AppData\Roaming\.minecraft\assets\extracted" # エクスポート先フォルダのフルパス

# ===================

$json = Get-Content $listjson
$list = ConvertFrom-Json -InputObject $json


foreach ($r in $list.objects.psobject.Properties) { 
    $fname = $r.Name
    $afname = $list.objects.$fname.hash

    $hash_dirname = $afname.Substring(0, 2);

    $from = $objects_dir + '\' + $hash_dirname + '\' + $afname;
    $to = $exportdir + '\' + $fname;

    $destdir = Split-Path $to -Parent;
    
    if (!(Test-Path -Path $destdir)) { $0_ = New-Item $destdir -Type Directory }
    Copy-Item -Path $from -Destination $to
}
```

汚いコードですが概ねこのような形です。先頭の３行(改行含め４行)を書き換えて利用してください。

# 注意点・解説
　先ほども説明した通り、JSONでリストが作られています。そのため、`ConvertFrom-Json`で簡単に読み込むことができました。しかし、いくつか注意点があります。

## PowerShell 5.1ではJSONをHashtableにできない
　Windows 10に標準搭載されているPowerShellは`-AsHashtable`オプションに対応していません。そのため、`PSCustomObject`で出力されたオブジェクト名をそのまま取得することができません。
　これを解決するために、foreach文では`psobject.Properties`を取得したいオブジェクトにつけることによって、プロパティのデータをforeachにかけています。
　これによって取得したオブジェクト名をそのまま埋め込み、`$list.objects.$fname.hash`とすることによってPSCustomObjectのままでデータを取得しています。

## ファイルコピー時に親ディレクトリがない
　PowerShellの`Copy-Item`コマンドレットは親ディレクトリを自動的に作ることはできません。そのため、`Split-Path $to -Parent`で親ディレクトリを取得し、当該ディレクトリがなかった場合は、新しくディレクトリを作成しています。

## ディレクトリ作成時のログ
 `New-Item`コマンドレットを使用すると、実行時に結果としてディレクトリの詳細データを出力します。しかし、今回は邪魔なだけなので、`$0_`変数に結果を代入させることによって表示をなくしています。
Rails開発で役立つVSCodeの拡張機能

#プログラミングの勉強日記
2020年8月7日　Progate Lv.226
VSCodeでRailsアプリケーション開発するうえで便利だなと思った拡張機能をまとめてみる。

#VSCode拡張機能のインストール方法

<img width="837" alt="0807.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/300b3463-0bc3-1d2b-fa49-fe2596e1a866.png">

1. 左端のバーから拡張機能を選択する
2. 検索ボックスにインストールしたい拡張機能の名前を入力
3. インストールしたい拡張機能を選択し、インストールをクリック


#Rails開発で便利な拡張機能

##[Ruby](https://marketplace.visualstudio.com/items?itemName=rebornix.Ruby)
　Ruby言語のサポートをする。Rubyのベーシックなシンタックスハイライト（テキストエディタなどの文字表示に関する機能の1つで、特定のキーワードや記号を色を変えたりフォントを変えたりして見やすいように表示する）や入力候補を提供する。

##[Ruby Language Colorization](https://marketplace.visualstudio.com/items?itemName=groksrc.ruby)
　Rubyのシンタックスハイライトを提供する。

##[endwise](https://marketplace.visualstudio.com/items?itemName=kaiwood.endwise)
　Rubyを書くときに忘れやすい`end`を自動で入力してくれる。

##[Rails](https://marketplace.visualstudio.com/items?itemName=bung87.rails)
　Railsをサポートする。Railsのスニペット（コードの断片）やナビゲーションを提供する。

##[Ruby Solargraph](https://marketplace.visualstudio.com/items?itemName=castwide.solargraph)
　Rubyの入力予測をより強化してくれる。（Rails拡張機能を入れるとインストールされる）

##[Rails Go to Spec](https://marketplace.visualstudio.com/items?itemName=sporto.rails-go-to-spec)
　Windowsの場合は`Cmd + Shift + y`のショートカットで対応するspecファイルと行き来ができる。

##[ERB](https://marketplace.visualstudio.com/items?itemName=CraigMaslowski.erb)
　erbのシンタックスハイライトを提供する。

###[Slim](https://marketplace.visualstudio.com/items?itemName=sianglim.slim)
　Slim使ってる方はこちらで、、

##[Rainbow End](https://marketplace.visualstudio.com/items?itemName=jduponchelle.rainbow-end)
　`end`を色分けする拡張機能。

#参考文献
[VSCodeでRuby on Railsを開発するなら絶対に入れたいおすすめ拡張機能７選](https://justy.life/programming/recommended-vscode-plugin-for-ruby-on-rails/)
[VSCodeの拡張機能でRailsと仲良くなる](https://qiita.com/hakshu/items/98ed12c32da97474b68d#%E6%9C%80%E5%BE%8C%E3%81%AB)
DOMって何？

整理する為に記事にしました。

#DOMとは？

- **D**ocument **O**bject **M**odelの略で、HTMLやXMLを扱うための手法のこと。つまりプログラムとHTMLやXMLの間で橋渡しをする役割を持つ。

- 現在ではほとんどのWebブラウザがDOMを実装していて、Webページ上に仕込まれたスクリプト(クライアントサイド・スクリプト)やWebブラウザに実装された機能などからWebページ上の内容を読み取ったり簡単に編集することができる。

- Webブラウザに限らずDOMが実装されている環境であれば、同じようにHTMLやXMLを扱うことができる。

- DOMはW3Cによって標準化され、Level1からLevel3までの３段階で勧告されている。
  - Level1・・・XML1.0とHTML4.0xへの対応
  - Level2・・・XML1.0の拡張とXHTML1.0、スタイルシートのサポートなどの追加
  - Level3・・・XML1.0の拡張とDOMツリーの読み書き機能などの追加

- DOMでは対象となる文書の各要素を抽出して、それらを階層構造として扱う(DOMツリー)。
JavaScriptの基本文法

JavaScriptの基本文法について書いていきます。
rubyと比較しながら勉強していくといいと思います!!


・window.alert()
　ブラウザでアラートを表示させるメソッド。
　例）window.alert('こんにちは');

・console.log()
　ブラウザのコンソールにテキストを表示させるメソッド。
　デバックとしても使用。
　例）console.log('こんにちは');

・let, const
  　変数宣言の際に使用する。
　letは、後で書き換えることができる変数宣言であり、
　constは、後で書き換えることができない変数宣言ある。
　例）　let name = 'yamada';
  　　　console.log(name + 'さん、こんにちは今日');

・配列 [ ]
　例）let list = ['ruby','javascript','html'];

　①配列の要素の取得（今回はjavascript)
 　console.log(list[1]);

　②配列の要素数の取得
 　console.log(list.length);
 　この場合コンソールに３と表示される。

　③要素の追加
　上記の配列に
　list.push('css');
  　今回は４番目の要素としてcssが追加される。

　④要素の削除
　先頭の要素を削除する場合shiftメソッドを使用する。
　最後の要素を削除する場合popメソッドを使用する。


 


・オブジェクト　{}
例）let obj = { name: 'yamada', age: 25, address: 'tokyo' };
　　console.log(obj);


・条件式
　if (条件式1) {
  　// 条件式1がtrueのときの処理
　} else if (条件式2) {
  　// 条件式1がfalseで条件式2がtrueのときの処理
　} else {
  　// 条件式1も条件式2もfalseのときの処理
　}

※条件式は()でくくること
※条件式の後に続く波括弧{}内の処理が実行されること
※複数条件を指定する場合は、elseのあとに続けてif文を記述すること

・繰り返し処理
　for (let i = 0; i < 繰り返す回数; i = i + 1) {
  　// 繰り返す処理の内容
　}

・関数定義
 　関数宣言と関数式の二種類ある。
　例）// 関数宣言
 　function hello(){
  　console.log('hello');
 　}

// 関数式（無名関数）
  　let hello = function(){
  　console.log('hello');
　}

javascriptの基礎中の基礎ですが定着しきるまで復習したいと思います。
次回はもっと発展的な内容を書いていきたいと思います。
Azure CLI で Log Analytics ワークスペースの Customer ID と ShareKey を確認する

# Log Analytics ワークスペースの Customer ID と ShareKey を確認するコマンド
```bash:AzureCLI
# 対象の LogAnalytics の値をセットする
resourceGroupName={リソースグループ名}
workspaceName={ワークスペース名}

# Customer ID を表示する
az monitor log-analytics workspace show -g $resourceGroupName -n $workspaceName --query customerId -o tsv

# ShareKey (Primary) を表示する
subscriptionId=$(az account show --query id -o tsv)
az rest -m post -u https://management.azure.com/subscriptions/$subscriptionId/resourcegroups/$resourceGroupName/providers/Microsoft.OperationalInsights/workspaces/$workspaceName/sharedKeys?api-version=2020-03-01-preview --query primarySharedKey -o tsv
```

# 補足
## Azure ポータル上で確認できなくなったぽい？ので Azure CLI でのコマンドを残しておこうと思った
この記事書き起こし時点(2020/08/06)では Azure ポータル上から LogAnalytics ワークスペースの Customer ID と ShareKey が確認出来なくなってたのと、少し深いところにあって分かりにくいのでコマンドでの確認方法を残しておきます。
AWS CLIのスニペットを公開

aws-cliは便利ですが、ちゃんと使うには些か慣れが入ります。これからaws-cliをばりばり使っていこうと思っている方向けに（&備忘録用に）普段自分が使っているaws-cilのスニペットを公開します。

## EC2

- 対象のEC2インスタンスの情報を取得 

```
aws ec2 describe-instances --instance-ids ${INSTANCE_ID}
```

- 最新のAmazon Linux2 AMI

```
aws ec2 describe-images --owners amazon --filters 'Name=name,Values=amzn2-ami-hvm-2.0.????????.?-x86_64-gp2' 'Name=state,Values=available' --query 'reverse(sort_by(Images, &CreationDate))[:1].ImageId' --output text
```

- インスタンスタイプを一覧表示

```
aws ec2 describe-instance-types --query 'sort_by(InstanceTypes[].{InstanceType:InstanceType, Hypervisor:Hypervisor, Memory:MemoryInfo.SizeInMiB},&Memory)' --output table
```

- インスタンスを一覧表示

```
aws ec2 describe-instances --query 'Reservations[].Instances[].{Name: Tags[?Key==`Name`].Value|[0], InstanceId: InstanceId, Status: State.Name, InstanceType:InstanceType}' --output table
```

## Security Group

- SecurityGroupを一覧表示

```
aws ec2 describe-security-groups --query 'SecurityGroups[].{Name:GroupName, GroupId:GroupId, VpcId: VpcId}' --output table
```

## Cloudformation

- スタックを一覧表示

```
aws cloudformation list-stacks --query 'StackSummaries[].StackName'
```

- [スタックを指定]スタックのステータスを確認

```
aws cloudformation describe-stacks --stack-name ${STACK_NAME} --query 'Stacks[].{StackName: StackName, StackStatus: StackStatus}' --output table 
```

## VPC

- VPCを一覧表示

```
aws ec2 describe-vpcs --query 'Vpcs[].{Name: Tags[?Key==`Name`].Value|[0], VpcId:VpcId}' --output table
```

- Subnetを一覧表示

```
aws ec2 describe-subnets --query 'Subnets[].{Name:Tags[?Key==`Name`].Value|[0], SubnetId:SubnetId}|sort_by(@,&Name)' --output table
```

## IAM

- インスタンスプロファイルを一覧表示

```
aws iam list-instance-profiles --query 'InstanceProfiles[].{Name: InstanceProfileName, Arn:Arn}' --output table
```

## SSM

- SSM接続可なインスタンスを一覧表示

```
aws ec2 describe-instances --query 'Reservations[].Instances[?State.Name==`running`][].{Name: Tags[?Key==`Name`].Value|[0], InstanceId: InstanceId}' --output text
```

## ALB

- ALB名とDNS名を一覧表示

```
aws elbv2 describe-load-balancers --query "LoadBalancers[].{Name: LoadBalancerName, DNSName:DNSName}" --output table
```
【React Native】長押しタップ時の処理を実装したいなら、ButtonではなくTouchableOpacityを使う

こんにちは！
今回はReact Nativeにおける、長押しタップ時の処理について、お伝えしたいと思います。

開発環境
・Expo SDK 38(React Native 0.62)

## 長押しタップの処理は`onLongPress`を使う
`onLongPress`は`TouchableOpacity`コンポーネントのpropsに持っています。
基本的には`onPress`と使い方は同じです。

`onPress`との違いは、
`onPress`：通常のタップ時の処理
`onLongPress`：長押しタップ時の処理

## `onLongPress`の書き方
例として、長押しタップ時にアラートを表示する処理を実装したいと思います。

```javascript
export default function chatList() {
  return (
    <View>
      <TouchableOpacity
        onLongPress={() => {
          alert('長押しタップ成功！');
        }}
      >
        <Text style={{color: 'white', backgroundColor: 'blue', height: 30, fontSize: 30}}>
          ここを長押ししてください
        </Text>
      </TouchableOpacity>
    </View>
  );
}
```

実装したらこんな感じになります。
![ReactNative_長押しタップ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659719/d219c1e1-64c5-f375-d356-79b281d1a363.gif)

`TouchableOpacity`に囲われた部分（背景ブルー）であれば、どこをタップしても大丈夫です。

## `Button`コンポーネントでは`onLongPress`を使えない
`Button`コンポーネントでは長押しタップを実装できません。
例えば、以下のように記述した場合、タップしても`Opacity`が変わるだけで、何も起きません。

```javascript
export default function chatList() {
  return (
    <View>
      <Button
        title='モーダルを開きたい！'
        onLongPress={() => {
          alert('長押しタップ成功！');
        }}
      />
    </View>
  );
}
```

## React Native 0.63ではPressableが追加され、タップ時の処理をより細かく分けられるように
残念ながら、2020年8月6日時点ではExpo SDKに対応しておりません。
現時点での最新Expo SDK 38はReact Native 0.62です。

私も実装したことないので、公式ドキュメントのリンクだけ貼っておきます。ご興味のある方は見てみてください。
https://reactnative.dev/docs/pressable

## 参考文献
React Native 公式ドキュメント
https://reactnative.dev/docs/touchableopacity
JenkinsにAnsibleプラグインをインストールし、ジョブ実行する

##概要
JenkinsにAnsibleプラグインをインストールすることにしたので、
備忘録として残します。

##実行環境
OS:CentOS8
Jenkinsバージョン：2.235.3

##Jenkinsインストール

以下を参考にしてみてください。
[CentOs8 jenkinsをインストールする方法](https://mebee.info/2020/05/19/post-11430/)

##Ansibleプラグインインストール

まずは、Jenkins画面を開き、ログインする。
ログイン後、「Jenkinsの管理」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114409/eb8f55db-71d9-1193-a3b9-f349743d0968.png)

→「プラグインの管理」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114409/fd92e57a-7240-65e1-019e-5cbb57ee5b01.png)

→「利用可能」の検索欄で「ansible」と入力
　インストールのチェック欄にチェックを入れ、「再起動せずにインストール」ボタンを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114409/d1c3e230-7168-a801-e5d4-6ff7ad83434d.png)

インストール完了後、「ページの先頭へ戻る」ボタンを押下

##Jenkinsで実行用のAnsiblePlayBook作成

以下で作成したPlayBookをそのまま使用していこうと思います。
[CentOS8にAnsibleをインストールしてみた](https://qiita.com/tomotomo3/items/87a0b1e7d4ba3942b3e9)

ただし、今回はパスワード入力を省略させるため、
iniファイルにパスワードに関する情報は書き込んでしまいます。

```bash:ansible/ini/master.ini

cd <任意のフォルダ>/ansible
mkdir ini
ls -ltr
→iniフォルダが作成されていること

cd ini
vim master.ini

#以下を追記
[server]
VMローカルIP

[server:vars]
ansible_user=<ansibleを実行するユーザ名>
ansible_ssh_pass=<ansibleを実行するユーザにsshログインするためのパスワード>
```

また、fingerprintエラー対策として、以下を実施。
※セキュリティ的にオススメできないため、別途対策を検討予定
※以下を参考にさせていただきました。
[Ansible のインストールと管理対象サーバへの接続設定メモ](https://blog.apar.jp/linux/5117/)

```bash:/etc/ansible/ansible.cfg

#バックアップ取得
cp -p /etc/ansible/ansible.cfg /etc/ansible/ansible.cfg_org_bk
ls -ltr /etc/ansible/ansible.cfg*
→バックアップが作成されていること

vim /etc/ansible/ansible.cfg

#以下設定追加
#↓デフォルト
#ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s
#↓こちらを追加
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no
```
##Jenkins Job作成・実行

Jenkinsにログインしていることを前提で書きます。

 - 「新規ジョブ作成」ボタンを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114409/5e3d2959-dd8b-b1cd-ff47-4e1a33c01cf5.png)

 - item nameをつけて、「フリースタイル・プロジェクトのビルド」を選択して、OKボタンを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114409/8e3bd0d5-ec5b-b95e-dcef-a20f6f315e1c.png)

 - 「ビルド」→「シェルの実行」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114409/a617aa50-4717-0f3b-6f9b-5f1b7294b2a0.png)

 - Ansibleコマンドを入力

```
cd <任意のフォルダ>/ansible
ansible-playbook -i ini/master.ini ansible-test.yml
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114409/be5a5d03-284b-4bf7-674b-5a1a6b3bee87.png)

 - 保存ボタンを押下し、「ビルド実行」ボタンを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114409/2cdebbc2-fb52-e047-6ff1-01849337b784.png)

「最新のビルド」→「コンソール出力」を押下
→ローカルで実行した結果を同じ出力がされていることを確認

終了

##まとめ
Jenkins、Ansible両方とも無料で使えるものなので、使ったことがない方はぜひ1度使ってみてください。
GitHubでMiniMagickの脆弱性アラートが出た際の解決方法

# 現象
RailsアプリをGitHubにプッシュした所、mini_magickに関する脆弱性のアラームメールが届いた。
解決までの備忘録として残しておく。

# 問題と原因
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/682425/f88633c3-138c-1b64-e812-955d34597094.png)
mini_magickのバージョンが古く、フェッチされたリモートイメージファイル名がリモートコマンドの実行を引き起こす可能性があるとのこと。
解決するには、バージョンをアップグレードすれば良さそう。

## GemFileを編集する
```ターミナル:Gemfile
gem 'mini_magick',  '3.8.0'
```

現在のMiniMagickのバージョンは、3.8だったので
アラートにて提示されているように4.9.4以降をインストールするように修正する。

```ターミナル:Gemfile
gem 'mini_magick', '>= 4.9.4'
```
上記のように編集することで、4.9.4以降にアップグレードされるはず。

## bundle installする
```ターミナル:
bundle install
```
これでバージョンが変わっているはずなので、動作確認をして問題なければOK。
あとは、プッシュすればアラートが消えてました！
【Python】macOSでpipを使えるようにする

ラズパイだと`apt-get`でpipがインストールできますが、macOSでpipをインストールしたく、そこで詰まってしまったのでその備忘録です。
Homebrewで一発とか思ってたのですが、`brew install pip`ではインストールできません。[^1]

[^1]: ※筆者はHomeBrewが大好きです。

## 公式ページのインストール方法に従う

[公式のやり方](https://pip.pypa.io/en/stable/installing/)に従って、以下のcurlコマンドで `get-pip`というPythonファイルをダウンロードします。

```shell
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
```

ダウンロードした`get-pip.py`を実行するとpipがインストールされます。

```shell
$ python3 get-pip.py
```

## インストール完了

whichコマンドを叩いてパスが表示されるので、インストール自体は完了です。

```shell
$ which pip
/usr/local/bin/pip
```

## 環境

- macOS 10.15.5 Catalina
- pip 20.2.1
- Python 3.8.5 



## 参考サイト

- [pipインストールページ](https://pip.pypa.io/en/stable/installing/)
- [pipのgithubリポジトリ](https://github.com/pypa/pip)
Expressでの環境変数の設定

##環境変数を使う意義
①コード内のテキストをプレーンテキストから環境変数にすることでセキュリティ向上
②環境を変数に格納することでカスタマイズしやすくなる

##①セキュリティについて
APIキーなどの重要な情報をそのままコード内に書いてしまっていると、GitHubにアップした時に、丸見えになってしまう。


##②カスタマイズ性について
例）MongooseをMongoDBに接続する時

```javascript
const mongoose = require('mongoose')


mongoose.connect('mongodb=//localhost:27017/task-manager-api', {
  useNewUrlParser: true, 
  useUnifiedTopology: true,
  useFindAndModify: false
});

```
↓
このままだと、「'mongodb=//localhost:27017/task-manager-api'」という、ローカル環境のMongoDBに接続し続けることになる

→ローカル以外の環境にデプロイしても、ローカルのMongoDBに接続したままになってしまう。

##環境変数作成の準備

```
└── App
    ├── config           //環境を保存するフォルダ
    |      └── dev.env  //環境変数として認識されるファイル名     
    |
```

※gitにpushする時に、configファイルは.gitignoreしておく

<h6>・「dev.env」の設定</h6>

[npmパッケージ「env-cmd」](https://www.npmjs.com/package/env-cmd)を利用して環境変数を利用できるようにする。

```npm i env-cmd
```　

でインストール。

・「package.json」の変更
"scripts"に追記。

```json
"scripts": {
    "start": "node src/index.js",    //メインプログラムが書いているファイルへのパス
    "dev": "env-cmd -f ./config/dev.env nodemon src/index.js"　　//環境を書いたファイルへのパスと、メインプログラムを動かす時のコード
  }, 
```

※これで、ターミナルに「npm run dev」と入力するとアプリをスタートさせることができるようになる。

##環境変数の設定
<h6>・「dev.env」の設定</h6>
①Port番号
②MongoDBとの接続
③秘密にしたいAPIのキー

の３つを環境変数に設定

```
PORT=3010
MONGODB_URL=mongodb://127.0.0.1:27017/task-manager-api
JWT_SECRET=thisisaseacretformyapp
```

<h6>・コード側での設定</h6>
※環境変数の呼び出しは「process.env.(環境変数)」

①Port番号
元々「port = 3010」と記述していていた箇所を「port = process.env.PORT」へ変更

②MongoDBとの接続
元々「mongoose.connect('mongodb=//localhost:27017/task-manager-api', {...})」と記述していた箇所を「mongoose.connect(process.env.MONGODB_URL, {...})」へ変更

③秘密にしたいAPIのキー
元々「thisisaseacretformyapp」と記述していた箇所を「process.env.JWT_SECRET」へ変更
【Vue.js】vue-headの導入について

フロント開発をする中、head要素をvueで管理する方法として、
[vue-head](https://github.com/ktquez/vue-head)というライブラリを導入する機会があったので、備忘録としてまとめておく。

## 前提
[vue-router](https://router.vuejs.org/ja/guide/#html)を導入している事。
※この記事ではvue-routerについての解説は行いません。

## 手順
導入自体はとても簡単。
まずは`npmコマンド`でパッケージをインストール。

```
npm install vue-head --save
```

今回は`main.js`で読み込みます。

```main.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import VueHead from 'vue-head'

Vue.use(VueHead)
Vue.use(VueRouter)
```
あとは各ページのコンポーネント毎にタイトルとmetaタグ設定すればOK。

```home.vue

export default {
  head: {
    title() {
      return {
        inner: 'App',
        separator: '|',
        complement: 'page',
      }
    },
    meta: [
      { name: 'description', content: 'My description', id: 'desc' }
    ]
  }
    ...
  }
}

```
`router.js`で表示するページ毎のタイトルを定義しておいて、
複数ページで共有するコンポーネントがあれば、簡単にタイトルやmetaの切り替えが出来ます。

更に共通の内容があれば、Mixinする事でよりシンプルに書く事が出来ます。
【初心者でもわかる】親子関係が予め決まっている要素一覧

# どうも7noteです。今回は多くの要素の中で既に親子関係が決まっているタグを紹介していきます。

どうも7noteです。
この記事は以下へ引っ越しました。


https://naruweb.com/coding/parentchild/
【第0回】「みんなのポートフォリオまとめサイト」を作ります~宣言編~

## 関連記事
[【第1回】「みんなのポートフォリオまとめサイト」を作ります~着手編~](https://qiita.com/kiwatchi1991/items/62ecde8289887965aff3)
[【第2回】「みんなのポートフォリオまとめサイト」を作ります~SPA認証で死闘編~](https://qiita.com/kiwatchi1991/items/2fdd533236cd32237bb2)

## きっかけ
**「アウトプットしたいけど、何作ればいいんや？」**
**「オレの今の技術だと、どんなものが作れるんや？」**

プログラミング学習中こんな風に思って困ったこと、ありませんか？

**私はめちゃくちゃありました！**

Twitterを見てるとたまーにTLに誰かのアウトプット作品が流れてきたりしますが、それもちょうど今の自分のレベルに合ったものでないとなかなか参考にしづらい。

**じゃあQiitaはどうなんだ！？**ということで、Qiitaでたとえば「JavaScript アプリ」とか「JavaScript ゲーム」などのキーワードで検索しても、ソースコードしか載ってないパターンがほとんどで、あってもスクショ画像が１枚だけ。
せめて動かしてるデモのgif画像くらい見てみたいですし、実際にサーバーにアップしているURLが記事内にあって、実物を触れるパターンなんて全然ないなと感じていました。

しかし、プログラミングを始めて1年半ほど経ったので今なら分かりますが、**世の中には自分の成果物をネット上のどこかで公開している人がたくさんいます！**

**だってみなさん、ポートフォリオを持って転職活動しますでしょ？**

てことは、企業に見て触ってもらうために、実際に公開する人が多いと思うんです（**ローカルでしか動きません、だとなかなかアピールしづらいですしね**）

でも、ネット上に公開している人がたくさんいるはずなのに、**「ここにいけばみんなのポートフォリオが一度にたくさん見れる！わーい！」**みたいな場所ってない気がするんです（あったら教えてください）

**じゃあ、自分で作っちゃおう！**というのが今回の趣旨でございます。

**他人の成果物を見てみたい人** と **自分の成果物を他人に見てもらいたい人** 
双方にメリットがあるようなプラットフォームにしていきたいです。

１からサービス作ったことがない人にとっては、どういう手順で作っていくのかをリアルタイムで晒しているというのは多少なりとも参考になる人もいるのでは？と思い、「作ってみた」じゃなくて「これから作ります」というスタンスの記事にしてみました。

そして、作る過程を晒すことで、作っている最中からみなさんにアドバイスをいただいてよりよいサービスにしていきたいという作戦であります！**（ここ重要！）**

どうぞよろしく！


## 自己紹介
新卒で入った食品メーカーにて、チャーハン職人として製造現場でチャーハンを作りまくるみたいな仕事を6年くらいやって退職。
2019年4月よりプログラミング学習を開始。2019年10月よりフロントエンドエンジニアとして都内で働いております。今は某事業会社のいわゆる大規模開発といわれるような現場で開発をしています。

今回は、**「React,Reduxでなんか作る」**そして、**「アクティブユーザーのいるサービスを作る」**という２つの目的を達成すべく、サービス作りを進めていきます。

## 対象ユーザー

- 他の人の成果物を見てみたい人
- 自分の成果物を他の人に見てもらいたい人

## がんばりたいポイント

このサービス、まず成果物を公開してくれるユーザーがいないと始まらないんです。

なので、 **集客**という点が非常に重要になってきます。

今後自分が事業を何かやるにしても必ず集客は必要になってきます。その第一歩としてこのサービスのユーザーを増やしていきたい。

「何かに役立つはず…」と思いTwitterでの発信もコツコツ続けてきました。おかげさまでフォロワーも結構増えました。何かに役立てるとしたら、今ここだろうという気がします。

今の自分が本気で集客をがんばったらどれくらいのことができるのか、そんな**自分への挑戦**でもあります。

## 使用技術
- **フロントエンド**・・・React, Reduxを使う（マスト）、react-routerを使ってSPA（風）にする（できれば）
- **バックエンド**・・・Laravel

## 機能
やってくうちに増減あると思いますが、今んとここんな感じの予定。
まずは機能最小限で完成優先。

- ユーザー登録（１アカウントで成果物の投稿・閲覧両方可能）
- ログイン（SNS認証あり）
- ログアウト
- プロフィール編集
- ユーザー削除
- コンテンツ（成果物）登録
- コンテンツ（成果物）編集/更新
- コンテンツ（成果物）削除
- いいね
- フォロー


## 工数見積
**1人月（160時間）**
できるかなーどうかなー


## おわりに
これぞまさに **宣言駆動開発 ！！！**
先にやるって言っちゃうとやるしかなくなるので、おすすめです。
今後は１週間ごとくらいで進捗報告していこうかと思います。

日々の作業進捗はTwitterでつぶやいています
https://twitter.com/kiwatchi1991
Mac のテキストエディットでHTMLコードを書いてみて つまずいた

超ハイパースペシャル初心者の“ぴおにあ”でーす:v:

この度、プログラムのプの字も分からない私は、ブロックチェーンでサスティナブルな仕組みを作りたい！ という、その一心だけで無謀にもプログラムを学び始めることにいたしました〜〜〜:clap:ｲｴｰｲ

そんな決意をした早々、Twitterのフィードに流れてきた超初心者用の全3回講座、しかも“いまだけ無料”に超惹かれ、そっこーで申し込み　興味津々受講してみましたよ✨


講師は　黒澤（わろさわ）先生　https://qiita.com/kurosawa_kuro

お題は、
【基礎学習 HTML編 〜HTML + CSS + JavaScript + FirebaseによるTodoアプリ〜】


内容は、
先生のお手本サンプルコードをテキストエディットにコピペして、拡張子を「.html」にして保存し、Chromeのタブにドラッグ&ドロップ！！！

という、非常に優しい（はずの）レクチャーでした。

わろ先生の兄弟弟子たちは以下参照
https://qiita.com/kurosawa_kuro/private/aab2426b0c434c453df1
　

ちな、私の環境は MacOS Mojave 10.14.6　です。



　
 さて、テキストエディットを立ち上げて、わろ先生が用意してくれた超初心者向けの数行のサンプルコードをコピペして、
「ファイル」　ー　「保存…　」　と進みます。

拡張子を .html にして、デスクトップに保存（保存はどこでも大丈夫らしい）
そして、その書類をChromeのタブにポイッ！！！　どやっ！？
　
　　

そーなんです、ここでトラブル発生。。。
Chromeの新しく作成されたタブには、コードがそのまま表示されておりました。

![スクリーンショット 2020-08-06 21.29.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687198/c8056ada-74a0-c25f-19d1-c47c14ac1450.png)


ほぇ？

　
　
　正しくは⇩⇩⇩こーなるはず。
![スクリーンショット 2020-08-06 22.08.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687198/a9ab7770-939e-06a6-b195-8158f180b671.png)

　
　
　
一見表面上は間違いはない。
テキストエディットの環境設定などをいくつか変更しても解決しません。
　
グーグル先生にお伺いを立て、いくつか調べるうちに判明したことは
　
「一部Macのテキストエディットは、デフォルトが“リッチテキスト”フォーマットになっており、そのままだと拡張子をhtmlにすることで自動的に裏でコードに変換してしまう（故に見たままをブラウザで表現される/できる）。　そうしないためには、テキストのフォーマットを“標準テキスト”に変更する必要がある。」
　
とゆー、有難くも時代の変革を感じさせる情報でした。

（もうプログラミングは自動変換されるほど当たり前に使用されているのね、、、）　なーんて少し驚き、黄昏つつ、
おっしゃ！　ますます取り残されないように学ばねば:fist:　と気合が入ったのでした。
　
　　
さて、それでは標準テキストに変換すれば良い！　とドキュメントを一から作成し、最初の保存ページをみたところ、

![スクリーンショット 2020-08-02 3.22.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687198/36b2a893-9038-3c9b-c94c-f7fdad12a492.png)

　
私は最初に、ここでフォーマットを「Webページ（.html）」を選択したのでした。
ここが、ある意味トラップ🕷🕸　　保存は一旦キャンセルして、
　
　
超初心者さんは、保存の前に以下のように「フォーマット」　ー　「標準テキストにする」　で変更をお勧めします。

![Mac-texteditor_ss2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687198/c5858557-67b0-dc25-0e32-f8a687386e74.png)
　

![Mac-texteditor_ss3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687198/b2b65313-140c-0b11-4b95-3d77ea364881.png)
　
　標準テキストに変更したら、安心して先ほどの　「ファイル」　ー　「保存…」　へ
　
![Mac-texteditor_ss4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687198/e399e89b-3903-7427-ba86-4f8424cc8551.png)
　
　そうすると、あら不思議、保存の画面が違います。
　
　
![Mac-texteditor_ss5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687198/422186aa-8562-aae6-eaf3-291aeeb2d4d8.png)
　
　
　分かってしまえば、簡単なこと。
慣れたら、一回保存してから慌てずにリッチテキストフォーマットを標準テキストに変更もできるでしょう。
　
でも、超ハイパースペシャル初心者な私は、こんなことでも三時間ほど悩んでしまったのでした。
　
　（テキストエディットでなく、Cot Editor とか他のアプリ使えばいいじゃん、という意見は脇に置いて）
　
そんな私にわろ先生は、この経験をQiitaにまとめることを勧めてくださったのです⭐️
このまま　わろ先生の素晴らしさを書き始めそうなので、それはまたの機会にして、、、。
　
今後Macのテキストエディットで躓く方がいないよう、また私の未熟な記録としてここに記載しておきます。
（いつか、こんな日もあったな〜、、、と懐かしむ日が来ますように、笑）
Laravelでの楽なバリデーションテストの書き方


# 変更しやすいバリデーションテスト

DataProviderを使おう。
今回はブログ形式のサイトのバリデーションテストを想定したコードを書いてみます。

```PHP
<?php

use Faker;
use Illuminate\Contracts\Validation\Factory as ValidatorFactory;
use Illuminate\Validation\ValidationException;
use Tests\TestCase;

class IndexRequestTest extends TestCase
{
    /** @var ValidatorFactory */
    protected $validationFactory;

    /** @var Faker\Generator */
    protected $faker;

    /**
     * IndexRequestTest constructor.
     *
     * @param null   $name
     * @param array  $data
     * @param string $dataName
     */
    public function __construct($name = null, array $data = [], $dataName = '')
    {
        parent::__construct($name, $data, $dataName);
        $this->faker = Faker\Factory::create();
    }

    protected $title = '文字列';
    protected $desc = '本文';

    protected function setUp(): void
    {
        parent::setUp();

        $this->validationFactory = $this->app->get(ValidatorFactory::class);
       
    }

    /**
     * @group authorize
     */
    public function testAuthorizeShouldReturnTrue()
    {
        $this->assertTrue($this->formRequest->authorize());
    }

    /**
     * @return array
     */
    public function validDataProvider(): array
    {
        return [
            'passes::title:文字列' => [
                'title' => $this->title,
            ],
            'passes::desc:本文' => [
                'desc' => $this->desc,
            ],
        ];
    }

    /**
     * @param array $data
     *
     * @dataProvider validDataProvider
     */
    public function testValidationSucceed(array $data)
    {
        $validator = $this->validationFactory->make($data, $this->formRequest->rules());

        $validator->validate();

        $this->assertFalse($validator->fails());
    }

    /**
     * @return array
     */
    public function invalidDataProvider(): array
    {
        return [
            'failed::title:null' => [
                'title' => null
            ],
            'failed::desc:null' => [
                'title' => null
            ],
        ];
    }

    /**
     * @param array $data
     *
     * @dataProvider invalidDataProvider
     */
    public function testValidationFailed(array $data)
    {
        $validator = $this->validationFactory->make($data, $this->formRequest->rules());

        $this->expectException(ValidationException::class);

        $validator->validate();
    }
}

```

こんな感じに書けば、成功パターンと失敗パターンの返り値に追加していくだけでバリデーションテストが実装できます。