WebLogic Serverって何?

JPAって何?

JPAは、リレーショナルデータベースを使う時用のJavaフレームワークの仕様の定義です。

http://terasolunaorg.github.io/guideline/5.5.1.RELEASE/ja/_images/dataaccess_jpa_mapping.png
6.3. データベースアクセス(JPA編) — TERASOLUNA Server Framework for Java (5.x) Development Guideline 5.5.1.RELEASE documentation

Java EEだけではなくJava SEでも使えます。

JPAJava EEの「Enterprise Application Technologies」に含まれる技術仕様ですが、Servlet/JSPEJBなどと異なり、コンテナ・ベースのアーキテクチャを採用していないためJava SEでも利用可能です。
JPAの基礎1 - Qiita

データベースとJavaを関連付けてくれます。

https://builder.japan.zdnet.com/storage/2015/07/07/8ffc3bda4c104f848f0979154e31cfd1/image5.png
初めてのJPA--シンプルで使いやすい、Java EEのデータ永続化機能の基本を学ぶ - builder by ZDNet Japan

JPAは以下3つの要素から構成されています。

Entityクラスは、データベースにあるテーブルを表すJavaのクラスです。

データベースにある1つのテーブルの1レコードを表すクラスです。
このクラスのインスタンス
データを格納してテーブルを更新したり、
テーブルから取得したデータを格納して使います。

永続性コンテキストは、Entityクラスのインスタンスを集めたものです。

この永続性コンテキストとJPQL*1を使用してデータベースへの問合せを行います。

EntityManagerは、Entityのライフサイクルを管理するためのAPIを提供するインタフェースです。

https://builder.japan.zdnet.com/storage/2015/07/07/13f730bf2cc2d33fca20efa3b6979098/image6.png
初めてのJPA--シンプルで使いやすい、Java EEのデータ永続化機能の基本を学ぶ - builder by ZDNet Japan

JPAの実装

EclipseLink
Hibernate ORM : JPAの仕様作成にHibernateプロジェクトの創始者がいたため、JPAHibernateの影響を受け継いでいます。
Apache Open JPA

*1:Java Persistence Query Language : SQLに似た問合せ言語

アプリケーションサーバとJava EE

アプリケーションサーバ

  • 英語 : Application Server

ビジネスロジックなどを実装したアプリケーションソフトウェアを実行することを専門とするコンピュータネットワーク上のサーバコンピュータ、もしくはそのようなコンピュータ上でのアプリケーションの実行を管理補助するミドルウェアのこと。
ウェブアプリケーションサーバは、ウェブクライアントからのHTTPのレスポンス要求を処理するWebサーバとバックエンドのデータベース中核層への橋渡しを担い、データの加工などの処理を行う。
プログラムの実行環境やデータベースへの接続機能、複数の処理を連結するトランザクション管理機能などを持ち、業務の処理の流れを制御するビジネスロジックを実装しているのがアプリケーションサーバである。
旧来の、クライアントやバックエンド側にビジネスロジックを実装する方式(2階層システム)に比べ、システムの変更や更新、増強などが容易で、柔軟性が高い。

f:id:ponsuke_tarou:20190604224300p:plain
親水公園の猫

アプリケーションサーバのいろいろ

Java EE アプリケーションサーバは、「Java EEに準拠したアプリケーションサーバ」のこと

たとえば・・・
WebLogic*1JBoss、WebSphere、GlassfishCosminexusGeronimoiPlanetOracle 9iAS

.NETフレームワークに準じたアプリケーションサーバ

たとえば・・・
Internet Information Services (IIS) 、Base4アプリケーションサーバZope

その他のアプリケーションサーバ

Java EE以外の言語セット・フレームワークを使用し、ビジネスロジックを実装し得るアプリケーションサーバ

f:id:ponsuke_tarou:20190604224332p:plain
花壇の豆

Java EE は、Javaシステム開発するための標準仕様です。

  • 正式 : Java Platform, Enterprise Edition

Java拡張機能セット
コミュニティ主導のエンタープライズ・ソフトウェアの標準です。Java EEJava Community Processを使って開発されており、業界の専門家、営利団体オープンソース団体、Javaユーザー・グループ、さらに数え切れないほど多くの個人が貢献しています。
Java EE の概要

JavaでWebアプリケーションを中心とした業務アプリケーションを構築するために選定された数々の仕様と、その実装
Java EE 6 環境の構築 (1/4):CodeZine(コードジン)

サーバー中心の複数層アプリケーションの開発、デプロイおよび管理にかかるコストと複雑さを大幅に削減する組織的なテクノロジのセットを含み、広く使用されているプラットフォーム(標準仕様)です。Java EEJava SEプラットフォーム上にビルドされ、移植可能、堅牢、スケーラブル、信頼性、およびセキュリティに優れたサーバー側アプリケーションを開発および実行するための一連の API を提供します。
Java EEおよびJava Webの学習 - NetBeansチュートリアル、ガイドおよび記事

規定されている機能

Java Servlet
  • サーバ上でウェブページなどを動的に生成したりデータ処理を行うために、Javaで作成されたプログラム及びその仕様
  • (Java EE 7) JSR-340
Java Server Pages ( JSP)
  • HTML内にJavaのコードを埋め込んでおき、Webサーバで動的にWebページを生成してクライアントに返す技術
  • Javaのコードは、<%と%>記号で囲まれた部分に書かれる(スクリプト言語チックにJavaを書く)
  • JSR-53

Java Servletとの違いは、記述方法にあり!
例えば、画像を表示する・・・

  • Java Servlet : Javaプログラムと同様に作成
    • out.print("<img src=\"/img/" + img.getName() + "\">");
  • JSP : HTMLにタグをつけて入れ込む
    • < img src="/img/<%= img . getName ( ) %>">

他にもいろいろ比較して特徴を知ろう!
出展 : JSPの特徴を理解する:Tomcatを使う「JSPプログラミング」(1) - @IT

比較対象 JavaScript JavaScript
同じところ HTMLにタグを入れて使う -
違うところ - 実行するところ
JSPの場合 <% %> サーバ側
比較対象の場合 <script> </script> クライアント側
  • vs Java Applet*2
    • 違うところ
      • 実行するところ
        • JSP : サーバ側
        • Java Applet : クライアント側(アプレット自体はサーバにおいてあるが使う時にクライアントに持って行って実行する)
  • vs CGI*3
    • 同じところ
      • 実行するところ
        • JSP : サーバ側
        • CGI : サーバ側
    • 違うところ
      • 使えるプログラム言語
      • 起動の仕方
        • JSP : 複数アクセスがあっても1度起動していればその内部で実行
        • CGI : アクセスがあるたびに新しいプロセス起動
  • vs ASP*4
Java Server Faces ( JSF)
Java Naming and Directory Interface ( JNDI)
  • ネーミング・サービス / ディレクトリー・サービス を扱うためのインターフェイスを規定した仕様
  • ディレクトリ・サービスが提供するデータやオブジェクトを名前で発見し、参照するのためのAPI
  • 他システムに対するインターフェースであり、具体的な実装からは独立している
  • サービス・プロバイダ・インターフェース(SPI)が規定されており、フレームワークディレクトリ・サービスの実装をプラグインすることができる
  • ディレクトリ・サービスの実装はサーバでもフラットファイルでもデータベースでもよく、サービスの提供側が任意に選択できる
  • JSR-907
Java Transaction API ( JTA)
JPAは、リレーショナルデータベースを使う時用のJavaフレームワークの仕様の定義です。

ponsuke-tarou.hatenablog.com

ほかにもいろいろあります。

f:id:ponsuke_tarou:20190604230702p:plain
花壇のクレソン

*1:ponsuke-tarou.hatenablog.com

*2:クライアント側のWebブラウザ上で動作するJavaのプログラムです。 ブラウザは読み込んだHTML文書内に、アプレット読込を指示する記述があると、サーバに対してアプレットのプログラムを送るよう要求します。 要求を受信したサーバは、クライアントにプログラムを返します。 クライアントは、アプレットプログラムを受け取り、Webブラウザ上で実行します。

*3:e-words.jp

*4:e-words.jp

ストアドプロシージャって何?

ストアドプロシージャは、データベースへの複数処理を1つのプログラムにまとめたものです。

  • 英語 : stored procedure
    • stored : サーバー上に保管(ストア)されるという意味

e-words.jp

https://image.itmedia.co.jp/ait/articles/1703/10/si_plsql-01-1b.jpg
PL/SQLとは何か プログラムの特徴と基本構造を理解する (1/2):超入門「PL/SQL」(1) - @IT

プログラムは専用言語で書きます。

規格またはRMDB 言語
(標準SQLの規格)SQL99 SQL/PSM
Persistent Stored Module
Oracle Database PL/SQL
Procedural Language Extensions to SQL
Microsoft SQL Server Transact-SQL
T-SQL

ストアドプロシージャの友達にストアドファンクションがいます。

ストアドプロシージャは、戻り値がありません。

ストアドプロシージャやストアドファンクションを使うと複数処理を1回でできるので実行速度が早くなります。

https://2.bp.blogspot.com/-iovzQkOLg90/W986Mda8_uI/AAAAAAAByPw/fATEQTmMGskdtHKo6PtP0s3Y5Fg56P5bACLcBGAs/s640/2018-11-04_11h25_09.png
https://1.bp.blogspot.com/-lVOmCKoIt7U/W987oFnsvNI/AAAAAAAByQQ/id2tbYS86b8gpgw3K3vM0UhJg51tmtwBACLcBGAs/s640/2018-11-04_11h32_48.png
Oracle ストアド・プロシージャとストアド・ファンクションの基本と違い|Everything you do is practice


f:id:ponsuke_tarou:20190603204533j:plain
栃木県八幡自然研究路

コンピュータ化システムバリデーションってなんだろう?

ピュータ化システムバリデーションってなんだろう?

  • 英語 : Computerized System Validation
  • 略称 : CSV

製薬業界や医療機器業界で使われる品質保証のことです。

医薬品、医薬部外品、化粧品及び医療機器の開発、製造に使用されるシステムにが対象になります。

目的は、システムが意図したとおりに動作することを保証することです。

薬や医療機器の品質保証のために、システムの開発から導入および廃棄までを検証・文書化します。

CSVは、人間の生命に影響を与える医薬品や医療機器などの開発から製造において使用されるコンピュータ化システムが、正しく開発され導入され運用されることを確実に確認して証拠を残しておくことで、薬や医療機器の品質および品質保証に問題が無いことを保証することで、法的にもとても重要な要件となります。
バリデーション | ライフサイエンススクエア: 富士ゼロックス情報システム株式会社

http://www.ymc.co.jp/design/img/chromato/technicalguide/gmp_support/img_0002.png
GMPサポート・メンテナンス|分取LCシステム|株式会社ワイエムシィ

CSVにおけるバリデーションとは、製造工程及びその手順を検証して文書化することです。

バリデーションとは、目的とする医薬品を製造において医薬品の開発、製造プロセスが最適であるか、プロセスに妥当性があるかについての検証です。
CSVとは。コンピュータ化システムバリデーションとは

「バリデーション」とは、製造所の構造設備並びに手順、工程その他の製造管理及び品質管理の方法が期待される結果を与えることを検証し、これを文書とすることをいう。
医薬品及び医薬部外品の製造管理及び品質管理の基準に関する省令

バリデーションの対象となるのは、開発したシステム自体だけではなくそれを使用する業務プロセスも含みます。

医薬業界におけるバリデーションは、コンピュータシステムのみを対象とするのではなく、コンピュータ化されたシステムを対象とする必要がある。これをComputerized System Validation(CSV)と呼ぶ。
コンピュータ化されたシステム(Computerized System)とは、「コンピュータシステム」と「業務プロセス」を統合したものである。
「コンピュータシステム」は、ハードウェアとソフトウェアから構成され「業務プロセス」は、人、標準業務手順書(SOP)と、設備(例えば測定機器、CRF、筆記具など)から構成される。
コンピュータバリデーションとは イーコンプライアンス

一般工業製品の品質保証となぜ分けているのか?

一般工業製品の場合は「価格」と「品質」が比例します。
安ければある程度の不良は許容されます。

医薬品は、生命にかかわるため不良は許容されないから

医薬品の場合は「価格」にかかわらず「不良」は許容されません。
そのため、世界的にCSVへの取組が求められています。

日本には「医薬品・医薬部外品製造販売業者等におけるコンピュータ化システム適正管理ガイドライン」というCSVガイドラインがあります。

ガイドラインなので法的拘束力はありませんが、海外のガイドラインとも整合性があり世界的にも通用するものです。

このガイドラインは欧米のGAMP5やPIC/S等のCSVガイドラインと整合性があり、コンピュータ化システムの開発から検証、運用、廃棄までのライフサイクルの考え方を採用しています。
CSVとは。コンピュータ化システムバリデーションとは

歴史

*1:[読み方]はっしゅつ。起こること。あらわし出すこと。

SlackにAWSとPythonを使って簡単なアプリを作る記録

このサイトのやり方でアプリを作る

qiita.com

Slackで新規にアプリとボットユーザを作成する

  1. 「Create New App」ボタンから新規アプリを作成する。
  2. サイドメニューの[Bot Users]から新規ボットユーザを作成する。

AWSでLambda関数からCloudWatchにデバッグ用のログを出力するためのIAMロールを追加する

  1. f:id:ponsuke_tarou:20190507135118p:plain
    [IAM]画面を開く。
  2. f:id:ponsuke_tarou:20190507135340p:plain
    サイドメニューの[Role]を選択して[Create role]ボタンを押下する。
  3. f:id:ponsuke_tarou:20190507135531p:plain
    [AWS service]の[Lambda]を選択し、画面下の[Next: Permissions]ボタンを押下する。
  4. f:id:ponsuke_tarou:20190507135836p:plain
    [AWSLambdaBasicExecutionRole]を選択してロールを追加する。
  5. f:id:ponsuke_tarou:20190507140448p:plain
    Roleが追加される。

AWSでSlack Event APIの認証を行うLambda関数を作成する

  1. f:id:ponsuke_tarou:20190507141038p:plain
    コンソールで[Lambda]を選択する。
  2. f:id:ponsuke_tarou:20190507141332p:plain
    [Create a function]ボタンを押下する。
  3. f:id:ponsuke_tarou:20190507141453p:plain
    [Author from scratch]を選択して必要な項目を入力する。
    1. [Runtime]は、「Python 3.6」を選択する。
    2. [Permission]は、[Execution role]で「Use an existing role」を選択して[Existing role]で追加したIAMロールを選択する。
  4. f:id:ponsuke_tarou:20190507143045p:plain
    参考にしているQiitaページに記載されているコードとHandlerを転記して保存する。
    • エンドポイントを認証するためにSlackからリクエストが送られてきた際には、認証をとおすためにchalleng要素をレスポンスする必要がある。そのための処理。

AWSで新規にAPI Gatawayを作成する

Lambda関数を叩くためのエンドポイントとなるAPIを作成する

  1. f:id:ponsuke_tarou:20190507144320p:plain
    コンソールから[API Gateway]を選択する。
  2. f:id:ponsuke_tarou:20190507144525p:plain
    [Get started]ボタンを押下する。
  3. f:id:ponsuke_tarou:20190507144602p:plain
    [OK]ボタンを押下する。
  4. f:id:ponsuke_tarou:20190507145026p:plain
    内容を入力してAPIを作成する。

APIにPOSTメソッドを作成する

  1. f:id:ponsuke_tarou:20190507145810p:plain
    POSTメソッドを追加する。

デプロイしてエンドポイントを作成する

  1. f:id:ponsuke_tarou:20190507150340p:plain
    [Action]セレクトから「Deploy API」を選択してデプロイを行う。
  2. 画面上部にエンドポイントとなるURLが表示されます。

テストする

  1. f:id:ponsuke_tarou:20190508125412p:plain
    [Test]リンクを押下します。
  2. f:id:ponsuke_tarou:20190508125617p:plain
    [Test]ボタンを押下します。
  3. f:id:ponsuke_tarou:20190508125841p:plain
    Lambda関数が呼ばれてログが出力されました。
  4. f:id:ponsuke_tarou:20190508130138p:plain
    CloudWatchにもログが出力されました。

Slackで作成したAPIを設定する

  1. サイドメニューの[Event Subscriptions]を選択する。
  2. [Enable Events]を「On」にする。
  3. [Request URL]にエンドポイントとなるURLを入力する。
  4. [Subscribe to Bot Events]に「message.channels」か「message.groups」を追加する。
  5. [Save Changes]ボタンで保存する。

f:id:ponsuke_tarou:20190507151234p:plain

「message.channels」を設定することでボットユーザが参加しているパブリックチャンネルに投稿されたメッセージを取得できる

api.slack.com

「message.groups」を設定することでボットユーザが参加しているプライベートチャネルに投稿されたメッセージを取得できる

api.slack.com

パブリックチャンネルプライベートチャネルかを見分ける簡単な方法

Slackの画面横に表示されているチャネル名の横にあるマークを見るとわかる。

f:id:ponsuke_tarou:20190508152336p:plain
#マーク
f:id:ponsuke_tarou:20190508152400p:plain
鍵マーク
get.slack.help

ボットユーザをワークスペースに追加する

アプリをインストールする

f:id:ponsuke_tarou:20190507151911p:plain
サイドメニューの[Install App]を選択し[Install App to Workspace]ボタンを押下してインストールする。

チャネルにボットを参加させる

f:id:ponsuke_tarou:20190507152311p:plain
Slackの歯車マークから[Add people to チャネル]からボットを追加する。

メッセージをチャネルに投げるとAWSのCloudwatchのLogに内容が出力される

START RequestId: 24..................... Version: $LATEST
[INFO]	2019-05-08T06:11:48.565Z	24......................
{
    "token": "hogehoge",
    "team_id": "hogehoge",
    "api_app_id": "hogehoge",
    "event": {
        "client_msg_id": "hogehoge",
        "type": "message",
        "text": "chanelとgroupの違いがよくわからない",
        "user": "投稿したユーザID",
        "ts": "1557295907.016900",
        "channel": "チャネルID",
        "event_ts": "1557295907.016900",
        "channel_type": "group"
    },
    "type": "event_callback",
    "event_id": "イベントID",
    "event_time": 1557295907,
    "authed_users": [
        "hogehoge"
    ]
}
ログはLambda関数に書いた「logging.info(json.dumps(slack_event))」で出力される

ボットユーザがメッセージを投稿する機能を作る

AWSにOAuth Tokenを設定する環境変数を設定する

Slack APIの画面でOAuth Tokenを確認する
  1. サイドメニューの[OAuth & Permissions]を選択してOAuth Tokenを確認する。
    • OAuth Tokenは、ワークスペースにアプリをインストールした際に生成されている。
Lambda画面でOAuth Tokenを設定する環境変数を設定する
  1. [Lambda]の画面 > サイドメニューの[Functions] > 作成した関数 で関数の画面を開く。
  2. [Environment variables]にKEY「SLACK_APP_AUTH_TOKEN」「SLACK_BOT_USER_ACCESS_TOKEN」を入力して各OAuth Tokenを設定する。
  3. 画面右上の[Save]ボタンで保存する。

Lambd関数を更新する

  1. [Function code]に参考にしているQiitaページに記載されているコードを転記する。
  2. [Save]ボタンで保存する。
メッセージの投稿には、ボットユーザがメッセージを投稿できるchat.postMessageを使用しています。

api.slack.com

メッセージを投稿して動かしてみる

f:id:ponsuke_tarou:20190508154352g:plain
できあがり

MacのPhpStormでLaravelプロジェクトでPHPUnitをできるようにする記録

  • 環境
    • macOS Mojave バージョン10.14.4
    • Composer version 1.8.0

以前、Laravelのプロジェクトを作ったことがありましたが、今回はPhpStormを使ってやります。

ponsuke-tarou.hatenablog.com

PhpStormをインストールします。

  1. JetBeanのPHPStormのサイトからダウンロードします。
  2. ダウンロードしたPhpStorm-yyyy.x.x.dmgをクリックします。
  3. f:id:ponsuke_tarou:20190424223044p:plain
  4. f:id:ponsuke_tarou:20190424223107p:plain
  5. f:id:ponsuke_tarou:20190424223120p:plain
  6. f:id:ponsuke_tarou:20190424223133p:plain
  7. f:id:ponsuke_tarou:20190424223145p:plain
  8. f:id:ponsuke_tarou:20190424223205p:plain
    好きな色を選びます
  9. f:id:ponsuke_tarou:20190424223227p:plain
  10. f:id:ponsuke_tarou:20190424223239p:plain

新規にComposerプロジェクトを作成します。

# 事前にインストールしてあるComposerの場所を確認
$ which composer
/usr/local/bin/composer
  1. f:id:ponsuke_tarou:20190424223355p:plain
  2. f:id:ponsuke_tarou:20190424230607p:plain
    プロジェクトを作成するディレクトリとComposerの場所とpackageでLaravelを選択して作ります
  3. f:id:ponsuke_tarou:20190424234741p:plain
    プロジェクト作成中です。
  4. f:id:ponsuke_tarou:20190424235113p:plain
    プロジェクトが作成されました。

qiita.com

Composerがインストールされていない場合はPhpStormのサイトを参照して作成します。

以下サイトの[新しいComposerプロジェクトを作成するには] > [2. ダイアログで、プロジェクトのパラメータを指定します。] > [b. Composerコマンドの実行方法を選択します。]を参照
pleiades.io

Command line parameterで指定した「–prefer-dist」はLaravelをZIPでダウンロードするということです。

# こんなコマンドが動きます。
/usr/local/bin/composer create-project laravel/laravel /path/to/project/directory/tryPhp/composer --prefer-dist

kin29.info
getcomposer.org

Laravelのバージョンを確認します。

# ウィンドウの下にある[Terminal]またはMacのターミナルで確認します。
$ php artisan -V
Laravel Framework 5.8.14

LaravelにくっついているサーバでLaravelの初期画面を確認します。

# サーバを起動します
$ php artisan serve
Laravel development server started: <http://127.0.0.1:8000>
# 表示されたURLにブラウザでアクセスします。
[Wed Apr 24 23:58:16 2019] 127.0.0.1:51584 [200]: /favicon.ico

f:id:ponsuke_tarou:20190425000004p:plain
表示されました。

Xdebugをインストールします。

qiita.com

プロジェクトを設定します。

PHP language levelを使っているPHPのバージョンに合わせます。

# [PHP language level]用に使っているPHPのバージョンを確認します
$ php --version
PHP 7.3.1 (cli) (built: Jan 10 2019 13:15:37) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.1, Copyright (c) 1998-2018 Zend Technologies
    with Xdebug v2.7.2, Copyright (c) 2002-2019, by Derick Rethans
    with Zend OPcache v7.3.1, Copyright (c) 1999-2018, by Zend Technologies

# [CLI Interpreter]用に使っているPHPのディレクトリを確認します
$ which php
/usr/local/bin/php
$ ls -la /usr/local/bin/ | grep php
# 省略
lrwxr-xr-x    1 mana  admin       27  1 20 14:09 php -> ../Cellar/php/7.3.1/bin/php
# 省略
  1. [PhpStorm] > [Preferences...] > [Languages & Frameworks] > [PHP]を選択します。
  2. [PHP language level]を使っているPHPのバージョンへ変更します。
  3. [CLI Interpreter]の[...]ボタンでダイアログを開き、使っているPHPの場所を設定します。
    • f:id:ponsuke_tarou:20190507231840p:plain
      XdebugがDebuggerとして設定されます。
PHP language levelが非活性で変更できない場合の対応方法

qiita.com

PHPUnitは、プロジェクトを作ったときに配置されています。

プロジェクトの直下にあるcomposer.jsonを確認するとデフォルトでインストールされています。
venderディレクトリにもphpunitディレクトリが配置されています。

    "require-dev": {
        "beyondcode/laravel-dump-server": "^1.0",
        "filp/whoops": "^2.0",
        "fzaninotto/faker": "^1.4",
        "mockery/mockery": "^1.0",
        "nunomaduro/collision": "^2.0",
        "phpunit/phpunit": "^7.5"
    },
$ ls -l vendor/ | grep phpunit
drwxr-xr-x@  8 mana  staff  256  4 24 23:47 phpunit

f:id:ponsuke_tarou:20190506130945p:plain
venderディレクトリにもphpunitディレクトリが配置されています。

PHPUnitの設定をします。

(Macのターミナルを使う場合)PHPUnitのパスを通します。

# .bash_profileにphpunitのパスを書いて
$ echo 'export PATH="/Path/To/vendor/phpunit/phpunit:$PATH"' >> ~/.bash_profile
# 反映して
$ source ~/.bash_profile
# 確認します。
$ phpunit --version
PHPUnit 7.5.9 by Sebastian Bergmann and contributors.
パスはbin配下ではなくphpunit配下を指定します。

以前PHPStormを使わなかった時は、PHPUnitのPathにbin配下を指定しました。

$ echo 'export PATH="/Path/To/vendor/bin/phpunit:$PATH"' >> ~/.bash_profile

PHPUnitを使えるようにする。 - Qiita

今回はうまくいきませんでした。

$ echo 'export PATH="/Path/To/vendor/bin/phpunit:$PATH"' >> ~/.bash_profile
$ source ~/.bash_profile
$ phpunit --version
-bash: phpunit: command not found

シンボリックリンクが貼ってあるけどだめなのですね。

$ ls -la vendor/bin/
total 32
drwxr-xr-x@  6 mana  staff   192  5  6 14:50 .
drwxr-xr-x@ 47 mana  staff  1504  5  6 14:43 ..
-rwxr-xr-x@  1 mana  staff  6028  2 17 05:54 php-parse
lrwxr-xr-x   1 mana  staff    26  5  6 14:43 phpunit -> ../phpunit/phpunit/phpunit
-rwxr-xr-x@  1 mana  staff  4305 10 14  2018 psysh
lrwxr-xr-x   1 mana  staff    51  5  6 14:43 var-dump-server -> ../symfony/var-dumper/Resources/bin/var-dump-server

composer.jsonにautoloadの定義があることを確認します。

定義がなければ環境に合わせて定義します。

    "autoload": {
        "psr-4": {
            "App\\": "app/"
        },
        "classmap": [
            "database/seeds",
            "database/factories"
        ]
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    },

対応付けのためのクラスマップ生成を行います。

# クラスマップ生成
$ composer dump-autoload
Generating optimized autoload files> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: beyondcode/laravel-dump-server
Discovered Package: fideloper/proxy
Discovered Package: laravel/nexmo-notification-channel
Discovered Package: laravel/slack-notification-channel
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.                                                                                                           Generated optimized autoload files containing 3759 classes

# 確認します
$ cat vendor/composer/autoload_psr4.php
<?php

// autoload_psr4.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'phpDocumentor\\Reflection\\' => array($vendorDir . '/phpdocumentor/reflection-common/src', $vendorDir . '/phpdocumentor/reflection-docblock/src', $vendorDir . '/phpdocumentor/type-resolver/src'),
    'Zend\\Diactoros\\' => array($vendorDir . '/zendframework/zend-diactoros/src'),
    'XdgBaseDir\\' => array($vendorDir . '/dnoegel/php-xdg-base-dir/src'),
    'Whoops\\' => array($vendorDir . '/filp/whoops/src/Whoops'),
    'Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'),
    'TijsVerkoyen\\CssToInlineStyles\\' => array($vendorDir . '/tijsverkoyen/css-to-inline-styles/src'),
    'Tests\\' => array($baseDir . '/tests'),
    'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
    'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
    'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'),
    'Symfony\\Polyfill\\Iconv\\' => array($vendorDir . '/symfony/polyfill-iconv'),
    'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
    'Symfony\\Contracts\\' => array($vendorDir . '/symfony/contracts'),
    'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'),
    'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'),
    'Symfony\\Component\\Routing\\' => array($vendorDir . '/symfony/routing'),
    'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'),
    'Symfony\\Component\\HttpKernel\\' => array($vendorDir . '/symfony/http-kernel'),
    'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'),
    'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
    'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'),
    'Symfony\\Component\\Debug\\' => array($vendorDir . '/symfony/debug'),
    'Symfony\\Component\\CssSelector\\' => array($vendorDir . '/symfony/css-selector'),
    'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'),
    'Ramsey\\Uuid\\' => array($vendorDir . '/ramsey/uuid/src'),
    'Psy\\' => array($vendorDir . '/psy/psysh/src'),
    'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
    'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
    'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
    'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
    'PhpParser\\' => array($vendorDir . '/nikic/php-parser/lib/PhpParser'),
    'Opis\\Closure\\' => array($vendorDir . '/opis/closure/src'),
    'NunoMaduro\\Collision\\' => array($vendorDir . '/nunomaduro/collision/src'),
    'Nexmo\\' => array($vendorDir . '/nexmo/client/src'),
    'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
    'League\\Flysystem\\' => array($vendorDir . '/league/flysystem/src'),
    'Lcobucci\\JWT\\' => array($vendorDir . '/lcobucci/jwt/src'),
    'Laravel\\Tinker\\' => array($vendorDir . '/laravel/tinker/src'),
    'JakubOnderka\\PhpConsoleHighlighter\\' => array($vendorDir . '/jakub-onderka/php-console-highlighter/src'),
    'JakubOnderka\\PhpConsoleColor\\' => array($vendorDir . '/jakub-onderka/php-console-color/src'),
    'Illuminate\\Notifications\\' => array($vendorDir . '/laravel/nexmo-notification-channel/src', $vendorDir . '/laravel/slack-notification-channel/src'),
    'Illuminate\\' => array($vendorDir . '/laravel/framework/src/Illuminate'),
    'Http\\Promise\\' => array($vendorDir . '/php-http/promise/src'),
    'Http\\Client\\' => array($vendorDir . '/php-http/httplug/src'),
    'Http\\Adapter\\Guzzle6\\' => array($vendorDir . '/php-http/guzzle6-adapter/src'),
    'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
    'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
    'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
    'Fideloper\\Proxy\\' => array($vendorDir . '/fideloper/proxy/src'),
    'Faker\\' => array($vendorDir . '/fzaninotto/faker/src/Faker'),
    'Egulias\\EmailValidator\\' => array($vendorDir . '/egulias/email-validator/EmailValidator'),
    'Dotenv\\' => array($vendorDir . '/vlucas/phpdotenv/src'),
    'Doctrine\\Instantiator\\' => array($vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator'),
    'Doctrine\\Common\\Inflector\\' => array($vendorDir . '/doctrine/inflector/lib/Doctrine/Common/Inflector'),
    'DeepCopy\\' => array($vendorDir . '/myclabs/deep-copy/src/DeepCopy'),
    'Cron\\' => array($vendorDir . '/dragonmantank/cron-expression/src/Cron'),
    'BeyondCode\\DumpServer\\' => array($vendorDir . '/beyondcode/laravel-dump-server/src'),
    'App\\' => array($baseDir . '/app'),
    '' => array($vendorDir . '/nesbot/carbon/src'),
);

PHPUnitの設定ファイルとなるphpunit.xmlを確認します。

自動でできるなんて素敵ですね。

<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="vendor/autoload.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false">
    <testsuites>
        <testsuite name="Unit">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>

        <testsuite name="Feature">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./app</directory>
        </whitelist>
    </filter>
    <php>
        <env name="APP_ENV" value="testing"/>
        <env name="BCRYPT_ROUNDS" value="4"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="MAIL_DRIVER" value="array"/>
        <env name="QUEUE_CONNECTION" value="sync"/>
        <env name="SESSION_DRIVER" value="array"/>
    </php>
</phpunit>

PhpStormにPHPUnitを設定します。

  1. [PhpStorm] > [Preferences...] > [Languages & Frameworks] > [PHP] > [Test Frameworks]を選択します。
  2. リストに「Local」がない場合は[+]ボタンで追加します。
  3. [PHPUnit library]で「Use Composer autoloder」を選択してvenderディレクトリ配下のautoloder.phpへのパスを設定します。
  4. [Test Runner]で[Default configuration file:]にチェックを入れてphpunit.xmlへのパスを設定します。

テストコードを作る

以前作ったファイルを流用します。なのでLaravelのディレクトリ構成とかからとっても外れています。
qiita.com

テスト対象ソースのエディタ上からテストクラスを生成します。

  1. f:id:ponsuke_tarou:20190506154955p:plain
    テスト対象ソース上でコンテキストメニュー > [Go To] > [Test]を選択します。
  2. f:id:ponsuke_tarou:20190506155122p:plain
    [Create New Test...]を選択します。既にテストペアが存在する場合はそのテストソースも表示されます。
  3. f:id:ponsuke_tarou:20190506155343p:plain
    テスト対象のメソッドを[Geneate test method for:]から選択して[OK]ボタンを押下します。
  4. f:id:ponsuke_tarou:20190506155514p:plain
    テストクラスが生成されました。

継承しているクラスをPHPUnit\Framework\TestCaseへ変更します。

自動生成時はHPUnit_Framework_TestCaseとなっていますがエラーとなるため変更します。
tomomik.hatenablog.com

Macのデフォルトではバックスラッシュが円マークになる事があるので以下のサイトを見てバックスラッシュで記載します。
Macにおけるバックスラッシュ(\)の入力方法 - Qiita

<?php

namespace App;

use PHPUnit\Framework\TestCase;

class controlStdClassArrayTest extends TestCase
{
// 省略

自動生成されたメソッドへテストコードを記載して保存します。

<?php

namespace App;

use PHPUnit\Framework\TestCase;

class controlStdClassArrayTest extends TestCase
{

    public function testCreateStdClassArrayNew()
    {
        $target = new controlStdClassArray();
        $stdList = $target->createStdClassArrayNew();

        foreach ($stdList as $std) {
            $this->assertInstanceOf(\stdClass::class, $std);
        }
    }
// 省略

作ったテストコード用に設定を追加します。

  1. f:id:ponsuke_tarou:20190507233810p:plain
    上部にある[Add Configurations...]を押下します。
  2. f:id:ponsuke_tarou:20190507234037p:plain
    [+]ボタンで表示されるテンプレートから[PHPUnit]を選択します。
  3. f:id:ponsuke_tarou:20190507235136p:plain
    各項目を入力して設定を追加します。

PHPUnitでテストコードを実行します。

f:id:ponsuke_tarou:20190507235717p:plain
[▶]ボタンで実行できます。

デバックしてブレークポイントで止めることもできます。

f:id:ponsuke_tarou:20190508000342p:plain
受話器マークをクリック後に虫ボタンでデバック実行してブレークポイントで止めることができます。