E2Eをやってみて感じたこと

E2Eテストとは

  • いわゆるシナリオテスト
  • User Interface Testとも呼ばれる
  • システム全体を通してテストをおこなう
    • ユーザと同じようにブラウザを操作し挙動が期待通りになっているか確認する

簡単な具体例

  • ログインページの場合
    • ログイン画面を表示
    • メールアドレス/IDを入力
    • パスワードを入力
    • ログインボタンを押下
    • ログイン後のトップページに遷移していること

特徴

  • テストとしては上位レベル(難易度が高いとかそういう話ではない)
  • フィードバックが遅い(作るのにも時間かかるし実行に時間がかかるからなぁ)
  • 壊れやすい(UIテストやしHTML変えられたら死ぬ)
  • ユニットテストとは真逆
  • よく語られるピラミッド図 テストピラミッド
  • 上に行くほど遅く、コストが高い
    • 不安定

なぜ不安定になるのか

  • 外部依存
    • 通信
      • ネットワーク
      • データベース
      • ファイル
    • デザイン変更

今まで通っていたテストがすべて失敗する


不安定なE2Eテストがもたらす悪影響

  • 修正や調整などのコストがかかる
  • テストが落ちることを前提に考えてしまうようになる
    • ネットワーク
      • 通信待ちでテストがタイムアウトした場合
        例)大きなファイルのダウンロード処理
        環境依存しがち → それってもうテストする意味ないよね
        テストの処理を見直す必要がある
        例外を想定してユーザに通知

不安定なE2Eテストに対する対処法

  • テストを書き直す
    そのシナリオが正しいか、テスト設計やコーディング自体に改善点はないか確認する
  • ピラミッドの下層へ
    フィードバックも早く安定的に動作するユニットテストで担保できないか検討する
    すべての項目をE2Eでやる必要はなく、メリデメを考慮して設計を行う
  • テストの価値を見極める
    全てのユースケースを洗い出し自動テストを安定的に行うのは、コストが高くあまり現実的ではない
    不安定なものは捨て、手動テストすることを検討する

まとめ

なんかちょっとマイナス要素多めの記事になってしまいましたが、
じゃあE2Eやらなきゃいいじゃん」ではなく
メリット・デメリットをしっかり理解した上で導入することが大切だと思います。

テストピラミッドを意識して、テストの実装方針を決める。
単テで補えるところは単テで実施し、E2Eが必要なところはE2Eで実施し、手動で行うところは手動で行う。 何事も行き当たりではなく設計、検討することが大切だと感じました。

async / awaitをざっくり理解する

はじめに

前回に続き、今回はasync / awaitについてざっくり書いてみます。
最初に言っておきますが・・・

本当にざっくりです!!

対象者

JavaScript初学者、いまいちPromiseやasync / awaitがわからない人向けです。
非同期、同期処理について詳しく知りたい方は回れ右して下さい。

Promiseについてざっくり知りたい人は前回の記事を読んでみてください。

それでは書いていきます。

async / awaitとは

簡単に言ってしまうと、非同期処理を同期っぽく書くことができる魔法のコトバです。

asyncはPromiseを返し、awaitはPromiseの処理を待ち展開します。
以下のコードを実行してみてください。

console.log((async() => {return "AsyncFuncTest";})());

結果は以下のようになるはずです。

Promise { 'AsyncFuncTest' }

asyncがPromiseを返していることがわかると思います。

一方で、awaitはPromiseを待ち、展開します。 まずは以下のコードを実行してみてください。

const asyncFuncTest = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {resolve("3秒経過");}, 3000);
    });
};

const asyncFuncTest2 = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {resolve("5秒経過");}, 2000);
    });
};

(() => {
    console.log(asyncFuncTest());
    console.log(asyncFuncTest2());
})();

実行結果はこのようになると思います。

Promise { <pending> }
Promise { <pending> }

「3秒経過」も「5秒経過」も出力されることなく、
また、setTimeoutも利かず実行後パッと結果が出力されたことと思います。

では、Promiseを待ち、展開するawaitをつけて実行してみましょう。
ちなみにawaitはasyncの中でしか実行することができません。

asyncはアロー関数やfunctionの前につけて使用します。

const asyncFuncTest = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {resolve("3秒経過");}, 3000);
    });
};

const asyncFuncTest2 = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {resolve("5秒経過");}, 2000);
    });
};

(async() => {
    console.log(await asyncFuncTest());
    console.log(await asyncFuncTest2());
})();

実行結果を見てみると
順番通り「3秒経過」「5秒経過」と出力されたと思います。

この様に、awaitはPromiseを待ち、展開し同期っぽく実行できることがわかると思います。
Promiseで言うところの.thenみたいな役割ですね。

asyncはPromise、awaitはresolve、thenみたいな感じだと考えておけば充分だと思います。

これらをうまく組み合わせコーディングすることで、
コールバック地獄になってしまいがちなややこしい非同期処理も
同期っぽい処理になり直感的且つ簡潔に書くことができます。

いかがだったでしょうか?
もっと詳しく知りたい方は、
先人の方々が書かれているブログなども見ていただければよいのですが
ざっくり理解して実際に使ってみたい方には丁度いい内容になっていれば幸いです。

Promiseをざっくり理解する

はじめに

JavaScript嫌い・・・苦手でずっと避けてきたんですが
仕事でAWS Lambdaを使うことになり仕方なく勉強し直しました。

JavaScriptが苦手で非同期には苦労してきたので
初心者にもわかりやすい記事になっていると思います。
(私の理解ですので間違ったことを書いていればご指摘頂けると幸いです)

対象者

JavaScript初学者、いまいちPromiseasync / awaitがわからない人向けです。
非同期、同期処理について詳しく知りたい方は回れ右して下さい。

ザックリ理解したい人向けです。

それではどうぞ。

Promiseとは

  • 非同期処理を簡潔に書くことができるもの
  • コールバック地獄から解き放たれるもの
    この程度の理解で充分だと思います。

そもそも、コールバックって何?って人も多いと思います。
コールバック関数というのは、関数が実行された後に実行される関数のことです。

これだけ聞いても全くピンとこないと思いますので実際にコードを書いてみます。

(() => {

    setTimeout(() => {
        console.log("3秒経過");
    }, 3000);

})();

これを実行すると当然3秒後に「3秒経過」が出力されます。
では、3秒経過を出力した2秒後に「5秒経過」を出力してみましょう。

(() => {

    setTimeout(() => {
        console.log("3秒経過");
    }, 3000);

    setTimeout(() => {
        console.log("5秒経過");
    }, 2000);

})();

これを実行すると、、、

5秒経過
3秒経過

あれっ!?

不思議ですよね?順番通りに実行されていない。
これが非同期です。

実行自体は上から順番にされていますが、
setTimeoutは非同期のため3秒後の結果を待たず2秒後のプログラムが呼ばれます。

結果、1秒早く「5秒経過」が実行されてしまうのです。

では、どうすれば順番に出力されるのでしょうか?

(() => {

    setTimeout(() => {
        console.log("3秒経過");

        setTimeout(() => {
            console.log("5秒経過");
        }, 2000);

    }, 3000);

})();

これを実行すると、、、

3秒経過
5秒経過

ちゃんと順番通りに実行されましたね。
関数が実行されたあとに実行される関数。これがコールバック関数です。

コールバック関数があることで、非同期な処理でも同期的に実行することが可能になります。
では、何が問題なのか!?

ご覧の通り、引数の中で関数を書くためネスト構造になっています。

この程度のネストなら許容範囲かもしれませんが、
実際のプログラムでは深いネスト構造になってしまうような処理を書かなければならないことも多いハズ。
これがコールバック地獄です。

そこで誕生したのがPromiseです。

上記で書いた例をPromiseを用いて書いてみます。

(() => {

    const promise = new Promise((resolve, reject) => {

        setTimeout(() => {
            console.log("3秒経過");
            resolve();
        }, 3000);

    });

    promise.then(() => {

        setTimeout(() => {
            console.log("5秒経過");
        }, 2000);

    });

})();

これを実行すると3秒経過の後に5秒経過が出力されます。
resolve関数はPromiseを終了する関数です。引数を渡すことも可能です。
resolveしたあと、thenメソッドで次に実行したい関数を記述します。

でも、これだけじゃ旨味がわからないですよね?
しかし、以下のようにすることでthenメソッドをチェインすることができ、より非同期を直感的且つ簡潔に記述することができます。

const promiseTest = (output, delay) => {

    const promise  = new Promise((resolve, reject) => {

        setTimeout(() => {
            console.log(output);
            resolve();
        }, delay);

    });

    return promise;
};

promiseTest("3秒経過", 3000)
    .then(() => promiseTest("5秒経過", 2000))
    .then(() => promiseTest("6秒経過", 1000));

これでコールバック地獄からも開放され直感的に非同期を書くことができます。

いかがでしたか?少しPromiseについて理解できたでしょうか?
Promiseには他にもreject関数を使うケースやPromise.allといったものもあります。
詳しく知りたい方は、調べてみて下さい。

次回はasync / awaitについて書いてみます。

Laravel(Laradock)を使ってAuth機能を実装してみた

はじめに

ハマったところなどを忘れないように備忘録として書いています。
おかしなところがアレばご指摘頂けると幸いです。

前提

  • Dockerが使えること
  • Gitが使えること

環境

  • macOS High Sierra Ver.10.13.2
  • Laravel Framework 6.12.0

環境構築

1.Laradockをクローンするためのディレクトリの作成
$ mkdir MyApp && cd MyApp
2.LaradockをGitからクローン
$ git clone https://github.com/LaraDock/laradock.git

クローンが終わるとMyApp直下にlaradockディレクトリができています。
laradockのディレクトリに移動して、ls -alするとlaradockに内包されているものが一覧で確認できます。

3.laradock配下にあるenv-exampleを.envにして任意で編集
cp env-example .env

今回、GUIツールのSequel Proでデータベースに繋ぎたかったのでMySQLは5.6を使用しています。
データベース名やユーザ名など、任意で設定してください。

### MYSQL #################################################

MYSQL_VERSION=5.6
MYSQL_DATABASE=default
MYSQL_USER=root
MYSQL_PASSWORD=secret
MYSQL_PORT=3306
MYSQL_ROOT_PASSWORD=root
MYSQL_ENTRYPOINT_INITDB=./mysql/docker-entrypoint-initdb.d

docker-composeコマンドでコンテナをビルド、起動します。

$ docker-compose up -d nginx mysql php-fpm

初回起動時は結構時間がかかると思います。
起動が終わるとdocker-compose psでコンテナのプロセスを確認します。

           Name                          Command              State                    Ports
--------------------------------------------------------------------------------------------------------------
laradock_docker-in-docker_1   dockerd-entrypoint.sh           Up      2375/tcp, 2376/tcp
laradock_mysql_1              docker-entrypoint.sh mysqld     Up      0.0.0.0:3306->3306/tcp
laradock_nginx_1              /bin/bash /opt/startup.sh       Up      0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
laradock_php-fpm_1            docker-php-entrypoint php-fpm   Up      9000/tcp
laradock_workspace_1          /sbin/my_init                   Up      0.0.0.0:2222->22/tcp

コンテナが立ち上がっていればOKです。

4.プロジェクトの作成

以下のコマンドでコンテナにアクセスします。

$ docker-compose exec workspace bash

コンテナに入れたらまずはパッケージリストを更新します。

$ apt-get update

更新したら以下のコマンドでプロジェクトを作成します。

$ composer create-project --prefer-dist laravel/laravel MyProject

作成が完了したらlaradockと同階層にMyProjectが出来ています。
MyProject配下にあるstorageとcacheのディレクトリのパーミッションを変更します。

$ chmod 777 storage
$ chmod 777 bootstrap/cache
5.プロジェクトの設定

手順通りに進めていれば、現在workspaceのコンテナに入っている状態なのでexitでコンテナから出ます。
コンテナから出た後、立ち上げたコンテナを以下のコマンドで停止します。

$ docker-compose stop

コンテナを停止したらコードのパスを設定するためlaradock配下にある.envを編集します。

### Paths #################################################

# Point to the path of your applications code on your host
APP_CODE_PATH_HOST=../MyProject/

上記の様にしておくことでworkspaceのコンテナに入った時のルートディレクトリの位置が変わってるはずです。

MyProject側の.envも以下のように編集します。
私の場合、DB_HOSTをmysqlにしないとconnection refusedのエラーが出て繋がらなかったです。

DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=default
DB_USERNAME=root
DB_PASSWORD=root

ここまで設定した後、再度コンテナを起動させブラウザでhttp://localhostへアクセスします。

$ docker-compose up -d nginx mysql php-fpm

もし、404の画面になった場合Nginxのドキュメントルートを変更します。
設定ファイルの場所はlaradock配下にあるnginx/sites/default.conf
変更箇所はline:13あたり

root /var/www/public;
6.パッケージリストのインストール

再び、workspaceのコンテナに入ります。

$ docker-compose exec workspace bash

コンテナに入ったらcomposerとnpmをインストールするだけです。

$ composer install
$ npm install
7.ログイン機能の実装

今回、ログイン機能はLaravel標準のものを使用します。
以下のコマンドを実行します。

$ artisan migrate

すると以下のようなエラーが出るかと思います。(※実行後の全文)

Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table

   Illuminate\Database\QueryException  : SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table `users` add unique `users_email_unique`(`email`))

  at /var/www/vendor/laravel/framework/src/Illuminate/Database/Connection.php:669
    665|         // If an exception occurs when attempting to run a query, we'll format the error
    666|         // message to include the bindings with SQL, which will make this exception a
    667|         // lot more helpful to the developer instead of just the database's errors.
    668|         catch (Exception $e) {
  > 669|             throw new QueryException(
    670|                 $query, $this->prepareBindings($bindings), $e
    671|             );
    672|         }
    673|

  Exception trace:

  1   PDOException::("SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes")
      /var/www/vendor/laravel/framework/src/Illuminate/Database/Connection.php:463

  2   PDOStatement::execute()
      /var/www/vendor/laravel/framework/src/Illuminate/Database/Connection.php:463

  Please use the argument -v to see more details.

MySQLのリファレンスを見てみると以下のように書かれています。

デフォルトでは、単一カラムインデックスのインデックスキーを最大で 767 バイトにすることができます。

つまり、768バイト以上のカラムに対するインデックスキーは設定できません。
Laravel 5.3まではUTF-8だった為、1文字が3Byteなのでvarchar(255)は、255文字×3Byte=765Byteということでインデックスを設定することができていましたが、
Laravel 5.4以降はUTF-8mb4となり1文字が4Byteとしてあつかわれるため、制限の767Byteを超えてしまいエラーとなります。

ちなみに、MySQL5.6を使っていることも影響しているので5.7で設定していればこのエラーは出ないかと思います。

今回私は絵文字を使用することを諦め、UTF-8として使用することにしました。 修正箇所はconfig/database.phpです。

'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',

以下のように修正。

'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',

中途半端にマイグレーションが実行されている為、MySQLのコンテナに入りMySQLにログイン。一度作られたテーブルを削除してから再度workspaceのコンテナでマイグレーションを実行します。

すると無事に以下4つのテーブルが出来ているはずです。

  • failed_jpbs
  • migrations
  • password_resets
  • users

続いて、以下のコマンドを実行しauth機能を作成します。

$ artisan make:auth

すると次は以下のようなエラーが発生します。

Command "make:auth" is not defined.

Laravel 5系までは使えていたコマンドですが6系になるとなくなってるんですね。 そこで以下のコマンドを実行します。

$ composer require laravel/ui --dev
$ artisan ui vue --auth

これで画面右上に登録・ログインボタンが出来上がったと思います。

実際にLOGIN或いはREGISTERをクリックしてみるとちゃんとページは遷移できます。 しかし、Laravel 6系ではCSS / JSが同梱されなくなっているためJSやCSSがあたっていない状態になっているかと思います。

そこでプロジェクト内で使用したい構成にあわせて以下から選択して実行します。 なお、vue/react/bootstrap以外にも任意のプリセットを用意したい場合、 \Laravel\Ui\UiCommand にマクロを実装することで追加が可能とのことです。

# VueやReactを利用しない、Bootstrap(+jQuery)のみのプリセット 
$ artisan ui bootstrap --auth 
# Bootstrapに加えてVue.jsを利用する 
$ artisan ui vue --auth 
# Vue.jsではなくReactを利用する 
$ artisan ui react --auth

生成したプリセットはコンパイルする必要があるため環境に合わせてビルドします。

# with npm
$ npm i
# 開発用ビルド
$ npm run dev
# 本番用ビルド
$ npm run prod

# with yarn
$ yarn install
# 開発用ビルド
$ yarn dev
# 本番用ビルド
$ yarn prod

画面を確認するとJS、CSSもあたりきれいに表示されていると思います。
登録、ログインが実際に動いていることを確認できれば完成です。

参考

qiita.com larapet.hinaloe.net

独習たった2日!ITIL V3 Foundation合格!

然程難易度が高くない

だけど何度も不合格になってしまう人がいるのも事実。

 

僕が実践したITIL V3 Foundation

試験勉強について紹介します!

 

落ちてしまった人、

これから受験しようと考えている人に

少しでも力になれれば幸いです。

ITIL V3 Foundationとは何か? 

簡単に言うと、

ITサービスマネジメントにおける

国際認定資格で基本的な知識を持っている事の証明になります。

 

IT統制における基礎知識だったり、

システム運用の考え方、在り方などを学びます。

 

おすすめ参考書

 僕が勉強に使用した参考書は2冊。

黄本と白本。

特に黄本は必須だと言う人も多く、有名ですね。

僕も実際、黄本は必須だと感じました。

 

その理由は後に記します。

 

試験方式

PCによる四者択一で、制限時間は60分。

65%以上の正解で合格になります。

 

PCでのマウス操作なので

ミスのないように気を付けましょう。

 

資格取得までの経緯

何故、僕がITIL V3 Foundationを受験したかというと

システムエンジニアだけど、開発だけではなく

運用についてもしっかりと学び、サービスの向上に繋げたかったから

 

 

と言うのは、建前で

会社にしっかりと運用を理解している人間がおらず

システムを運用する中で、事業側に理解を得られないことも多く

また、何か伝えようとしても説得力にも欠けるなと考えたからです。

 

プロメトリックとピアソン

EXIN認定試験を受けられるのが、プロメトリックとピアソンVUEです。

 

両社に違いはありません。金額も難易度も同じです。

しかし、僕はピアソンではないといけない理由があったので

ピアソンから申し込みを行い受験しました。

 

なぜ、ピアソンにしたのかというと

極論、前日でも申込みが出来たこと。日曜日の受験が可能だったこと。

これだけの理由です。

少しでも勉強の時間が欲しかった。

 

受験までのスケジュール

僕が受験したのは2017/03/26(日)

普段、朝から晩まではSEとして働いているので

実際、勉強に使った時間は30時間ほどです。

 

 短期間での受験を考えている人は

覚悟して挑んだ方がいいです。

 

受験料も3万円弱と高いです!

  
  • 勉強初日 2017/03/24(金)

この日も仕事だった為、23時頃帰宅し、

2~3時間ほどの仮眠の後、まずは黄本を全部読むところから進めました。

 

まずは有無を言わさず一通り読むことが大切です。

専門用語や、感覚を掴むためです。

理解はその後でも遅くありません。

受験に合格するために優先順位を付けましょう。

 

一通り読み終えたところで、恐らく殆どの人が

力試しだと言ってネットの問題集に手を出してしまいがちですが…

 

ここでネットの問題集をやるのは気休めにもなりません!時間の無駄です!

 

ここまでで3時間位でした。

 

読み終えたことに満足して寝たくなりますが、2日間の我慢です。

読んだことを忘れない内に、ITIL脳になっている内に次のステップです。

 

2巡目、黄本をカラーペンを手に再度読み直します。

次は重要そうな箇所をマーキングしながら読み進めていきます。

 

専門用語や、1巡目分かりづらかったところ

頻繁に出てくる単語、サービスの関係など徹底してマークしていきます。

 

全てをマークし終えたところで朝10時を過ぎていました。

 

  • 勉強二日目 2017/03/25(土)

既に朝の10時を過ぎていますが、5~10分程度の仮眠を取り

眠気覚ましに熱めのシャワーを浴びました。

 

脳がITILから離れない内に続きを勉強します。

 

ここにきて今更ですが…

実は白本は触りのページしか読みませんでした。

 

何故なら、内容が細かく詳しく書かれているからです。

試験まで時間に余裕があり、

ITILを基礎からしっかり学びたい人にはオススメですが、

兎に角、今は時間がありません!受験に合格することが最大の目的なのです!

 

最初の方でも述べた、黄本が必須というのは

要点だけがまとめられており、用語と構成だけを効率的に学べるからです。

 

だから、短期間で受験をする人には黄本が必須なのです。

 

黄本、3巡目に突入。

3巡目は理解に努めます。

 

2巡目でマークしたところは大事な用語や、分かりづらかったところ

理解しなければならないところです。

 

時間をかけて、理解しながらマークしたところを読み進めましょう。

 

3巡目を読み終えたところで、

ようやく力試し!問題集を解いてみましょう。

 

自信がつくまで何度も何度も繰り返し問題を解きます。

わからなければ黄本を振り返りましょう。

 

ここで注意しておかなければならないこと、それは

黄本やネットにある問題集と実際の試験は全然違うということです。

 

僕も正直、試験を開始した時に焦りました…

全然違う…

 

しかし、落ち着いて下さい。

出題の言い回しが違うだけで答えは勉強していることと同じなのです。

 

  • 試験当日 2017/03/26(日)

前日は3時間ほど睡眠をとり、

この日の朝から問題集を一巡解きいざ試験会場へ。

 

受付を済ませ、作業的にパソコンの前に案内され試験開始。

 

60分フルフル時間を使い何度も見直し最後の終了ボタンを押すときは

本当に緊張しました。押した瞬間に合否がわかるからです。

 

結果は無事合格。

睡眠時間を削って勉強した甲斐がありました。

高い受験料も無駄にならず本当に良かったです。

 

今回は試験に合格することが最大の目的だったため

細部への理解は二の次となってしまいましたが、

資格取得を最優先に考えている人は是非参考にしてもらえればと思います。

 

次は、しっかりと理解を深め

1つ上のITILインターミディエイトにも挑戦しようと思います。