Postman に自動でAPIのレスポンスが正しいかどうかのテストを作ってもらう

Postman、APIなどのテストで使っている方も多いと思います!

すばらしいツールです。いつもお世話になっております!!😿

さて、先日Postmanさんのやっているイベントに行きまして紹介されていた

「APIのテストを自動で作成する」

というのを実践でやってみましたので、手順など含めて書いておきます。

例として、次のようなJSONをPostするとします。

{
	"id": "abc",
	"company_id": 123,
	"requestor_id": "0",
	"events": [
		{
			"id": "def",
			"type": "add",
			"object": {
				"type": "Route",
				"company_id": 123,
				"date": "2023-12-07"
			}
		}
	]
}

上記のPostは本来あるべきdriver_idが欠損しているので、失敗して次のようなレスポンスが返ってくるとします。

{
    "id": "1234",
    "request_id": "abc",
    "status": "failed",
    "error_infos": [
        "driver_idがありません。"
    ]
}

一旦、Postmanから最初のリクエストをPostします。

一旦、送信してResponseが返ってきますと、「Postbot」というのが立ち上がります。立ち上がらない場合は、右下のPostbotというところをクリックしても立ち上がります。

で、Postbotのメニューに「Test for response」というのがありますので、それをクリックすると、テストを作ってくれます。

そして、テスト というタブをクリックすると、なんとこれでテストができています。ありがたすぎるー!!

とはいっても、これが完璧なわけでもなく、エラーメッセージなどのテストはなかったため、追加します。

Postbotさんが提案してくれる 「Add more tests」 というリンクをクリックしてみると、次のテストまで作ってくれます。

pm.test("Error_infos array contains only strings and no null or undefined values", function () {
    const responseData = pm.response.json();
    
    pm.expect(responseData.error_infos).to.be.an('array');
    responseData.error_infos.forEach(function(error) {
        pm.expect(error).to.be.a('string');
        pm.expect(error).to.not.equal(null);
        pm.expect(error).to.not.equal(undefined);
    });
});

ぴええええ 何から何までお世話になっています!

しかし、まぁいうなればエラーメッセージのテストをしておきたいのですが、それは自分で追加する必要がありそうです。

なので、上記のテストに自分で追加します。

pm.expect(responseData.error_infos).to.be.an('array');
responseData.error_infos.forEach(function(error) {
    pm.expect(error).to.be.a('string');
    pm.expect(error).to.not.equal(null);
    pm.expect(error).to.not.equal(undefined);
    pm.expect(error).to.equal('driver_idがありません。'); // 追加
});

でも、自分で一から書くよりずっと楽ですよね!

テストを更新したら、テストが合格するか試したいですよね!
そしたら、次のテスト結果にあるぐるっと回るようなアイコンをクリックします。

これで、再度テストが試せて想定通りの動作をしていることがわかりました。

で、このテストは今後「送信」をクリックすると、自動で実行してくれるのでテストが失敗したか成功したか、常に把握することができます。

ちなみに、私はPostmanさんのMeetupというオフラインのイベントに行って上記の説明を教えて頂き、なんとタダで東京駅のおしゃれな夜景を見ながらおいしいご飯とお酒も頂いちゃいました!!しかもPostmanロゴのかわいいTシャツも!!!!(泣)
なんでそんなに気前がいいんですか(号泣)
もはや自分が乞食で恥ずかしいレベル(*ノωノ)
他のエンジニアさんとも交流が持てますし、オススメでしかありません!

↓にワークショップのリンクを貼っておきますので、興味がある方はぜひどうぞ。

https://postman.connpass.com/

Postmanさんのオフィス
Postmanさんのでらおしゃれなオフィス。東京駅の目の前です

Chromeデベロッパツール js、tsデバッグのちょっと便利な使い方

Chromeの開発者ツール、Web系の開発をしている方なら一度は触ったことがあると思います。

今回は、普通の使い方はもう知ってるよという人向けに、私が個人的に気に入っててちょっと便利な使い方を書いておきます。

①ブレークポイントを一時的に無効にする

サンプルスクリプトは下記です。

    const dog = {name: 'dog', age: 0}
    const monkey = {name: 'monkey', age: 1}
    const cat = {name: 'cat', age: 5}
    const animals = [dog, monkey, cat]
    animals.forEach(animal => {
      if(animal.name === 'monkey') {
        console.log('ウキー')
      }
    })

例えば、下記のような場所にブレークポイントを置いたとして

リロードのたびに実行されるのがなんかイヤだな…ってことがあると思います。

そういう時は、右クリックすると、次のようなメニューが出ますので

Disable breakpoint を選択すると、Enableにするまでこのブレークポイントで止まりません。

私は結構これを使います。

なんで使うかっていうと、ページのリロードって弊社では例えばVue使ってるんですが、コードの更新ごとにリロード走って結構頻繁に起こるんですよね。そのたびにブレークポイントで止まってるとかが面倒だからです。

あとは普通にループの中で、ループの1回目はブレークしたいけど、後はもういいよ…という場合などに使います。

「ブレークポイント自体もう一度クリックしたら消えるじゃん」

という声も聞こえますが、そうすると、またコード直して同じところにブレークポイントを付けたい、という場合にちょっと手間が発生します。

ちょっとの手間、惜しんでいきましょう!!

②ブレークポイントに条件を設定する

ループの中の例えばループの10回目以降だけ発言する不具合がある、などの場合にポチポチステップ実行を押していませんか?

ブレークポイントに条件を設定することができます。

ブレークしたい場所を右クリックしてください。

「Add conditional breacpoint」を選択します。

animal の age が 2より大きい時だけブレークするように設定します。

黄色いクエスチョンマークのブレークポイントができたらOKです。

これで、age > 2のcat の場合のみブレークするようになります。

③すべてのブレークポイントを一時的に無効にする

①で紹介したブレークポイントを一時的に無効にする、ですが、多くのブレークポイントがある場合に、いちいちDisableにしていくのは面倒だと思います。

そんな時に、一度に無効にできる方法があります。

下記の開発者ツールの右のほうにある電池のようなマークをクリックしてください。そうすると、ブレークポイントが一気に一時的に無効にできます。

また一気に有効にしたい場合は、同じマークをクリックすると、一気に有効になります。

後は、便利な使い方がもっとあると思いますが、公式サイトにも情報がいっぱいあるので、ぜひ見てみてください。

ブレークポイントでコードを一時停止する

TypeScript IDEの型推論がまだ適当なのかもしれない

最近TypeScriptを触り始めた私です。

ちょっとわかりづらかったことがあったのでメモ的に書いておきます。

私はIDEはPHPStormを使っていて、バージョンはPhpStorm 2023.2.4です。
PHPStormで設定しているTypeScriptのバージョンは5.1.3です。
Nodeのtscのバージョンは5.0.4です。

さてさて、次のようなTypeScriptがあるときに

    class Person {
      constructor(public name: string, public ramen?:string) { }
      talk() {
        console.log('最近どうですか?')
      }
      setRamen(ramen: string) : Person{
        this.ramen = ramen
        return this
      }
      build():Person {
        return this
      }
    }

    class Kyushujin extends Person {
      talk() {
        console.log('最近はなんばしよっとね?')
      }
      build():Kyushujin {
        return this
      }
    }

    const kyushujin =  new Kyushujin('太郎')
        .setRamen('とんこつ')
        .build()

    if(kyushujin instanceof Kyushujin) {
      console.log('九州人です')
    }

    kyushujin.talk()

実行結果は下記の通りです。

ちゃんとインスタンスkyusyujinは”Kyushujin”として認識されていますが、new Kyushujin の部分でIDEがしてくれる型推論は 下記のスクショのようにスーパータイプのPersonなんですよね。

PHPStormのスクショ① const kyushujin:Personとなっている

エッ ってなりましたね。TypeはKyushujinとして表示されるべきだと思ったからです。

これ、setRamen() で 戻り値の型が Personになってるからみたいで setRamen()をコメントアウトすると、Kyushujinとして推論してくれます。

PHPStormのスクショ② const kyushujin:Kyushujin となっている

実行結果は上記と一緒です。

一瞬、あれ?サブタイプにちゃんとなってないじゃん!って思って焦りました。

あんまりまだわかってないことが多いので、まだまだ勉強中です。(´ω`)

ちなみに余談で、弊社ではGithub Copilot 使ってますが、下記までタイプしたところで

    const kyushujin =  new Kyushujin('太郎')
        .setRamen(
 .setRamen('とんこつ')

って勝手にコパイロットくんが入れてくれたんですよ!!!

すごくないですか???Σ(゚Д゚)スゲェ!!

九州人のラーメンは ‘とんこつ’ を set する

を生成できるところまで来てるんですね。(`・ω・´)

PHPStorm デバッグの小技

弊社では、デフォルトではPHPStormというIDEを使っています。

で、下記に書くことは他のIDEでもできるかもしれませんが、今回検証やサンプルに使うのはPHPStormなので、タイトルが
「PHPStorm デバッグの小技」
となってますが、ほかのIDEでも同様の機能があるものはあると思います。

この記事は、普通のステップイン、ステップオーバーなどの基本のデバッグはもうできているというプログラミング中級者さん向けでお話していきます。

では早速。

①ブレークポイントの機能をうまく使う

1.ある例外が起こった時だけブレークするようにする

今回、この記事を書こうと思ったきっかけなんですが、こんな便利な機能があるのを私は知りませんでした!!

ある例外が起こった時に、エラーログで例外の起こるソースコードの場所はわかったとしても、パラメーターが多い場合など、どういう条件で例外が起こるのかがわからなかったりすると思います。

そんな時、例外が起こるまでステップオーバーをポチポチ押したりしていませんか?
この機能を使うと、例外が起きたときだけブレークしてくれます

次のサンプルスクリプトを使います。

<?php

$array = ['りんご','メロン','バナナ'];

foreach ($array as $key => $value){

    if($key === 2){
        throw new LogicException('バナナはダメ');
    }
    print $value;
}

やり方です。

①ヘッダーメニューのRun→View Break Points をクリック

②下記図のような画面になるので、左上のプラスボタンをクリックし、PHP Exception Breakpointsをクリック

ブレークポイント一覧の画面 この画面で思っているより多くのことができる!!

③Exceptionの名前を入力  ここでは、LogicExceptionを入力します。

上記③までやってデバッグをしてみてください。下記のExceptionで止まります。

デバッグウィンドウは、次のようになっています。

便利!

2. 特定の条件の時だけブレークするようにする

ブレークポイントを設定してデバッグする際、例えば100回ループが回るとして、99回目で問題が起こるとして、98回ポチポチステップオーバーを回していませんか??

99回目に手っ取り早くワープする方法があります。ちなみに、ほかの方法でもできますが、それは後述します。

やり方です。

①ブレークポイントを右クリックします。

こいつ…!右クリックできるぞ…っ!

② Conditionとあるところに条件を入れます。ここでは、サンプルとして$keyが1の時だけブレークするようにします。

③ ?がついたブレークポイントのアイコンができました!

デバッグを実行してみてください。
$key が 0 の時をすっ飛ばして、$keyが1の時だけブレークしてくれます!

3. 何度も不要なブレークポイントでブレークするのを避ける

プログラムの流れを追いたい時、最初の1回だけブレークすればいい場合がありますよね。しかし、最初の一回だけでいいのに繰り返すループ処理があって、何度もブレークする時、
「ああ、面倒だな」
とつぶやきながら、ポチポチステップオーバーやResumeをしていませんか??
1回ブレークしたら、後はブレークしないようにすることができます。

①普通にブレークポイントを設定する

②例えば、最初のブレークだけで、後はもう必要ないという場合は、デバッグウィンドウのMute Breakpointsという串団子みたいなアイコンをクリックします。

♪団子、団子、団子、団子~

③Resumeをクリックすると、もうブレークポイントでブレークしません。

ブレークポイントも黒くなります

ただし、このやり方だと、ほかにもブレークポイントがあるときに一気にブレークしなくなります。
一部のブレークポイントだけ、1回ブレークされればよい、という場合を次に紹介します。

4. 1回だけブレークされればよいブレークポイントを作る

3のやり方で、1回ブレークしたら後はミュートという方法がありますが、一気にミュートされると困る、ほかのブレークポイントでは止まってほしい、という場合に使える方法です。

①普通にブレークポイントを設定する。

②Run → View Break Points とクリックすると、下記のようなペイン(表示領域のこと)が表示されます。①のブレークポイントをクリックして
Remove once hit
というチェックボックスにチェックをつけます。

そうすると、上記は例えば7行目と10行目にブレークポイントを設定していますが、7行目だけ Remove once hit にチェックします。

すると7行目では最初の1回にブレークしてその後ブレークポイントがなくなりますが、10行目では2回ブレークします。

4. 特定の値があった場合のみ、consoleに表示する

ブレークポイントを通った時に、変数が特定の値になる条件を知りたい場合があると思います。

そんな時にこれが使えそうです。先程から何度か登場している、ブレークポイントペイン。皆様、もうこいつと仲良しですね?

実はLogという機能があり、さらにはそれに式を入れることができます。
$valueがメロンになるときがいつなのか、記録したい時があったとします。

$value ==’メロン’と入れておく

すると、デバッグコンソールに次のように表示されます。

2回目のループだけ、1と表示されているのがわかるでしょうか?


$value がメロンの時だけ1が表示される

2. 特定の条件の時だけブレークするようにする と似ていますが、こっちは例えばループをざっと回して、どういうパターンの時に値が〇〇なのか、などを俯瞰で見たい時などに使えると思います。

②変数の中身を書きかえる

ハァハァ… ブレークポイントだけで、結構もりだくさんでしたね💦

これはメジャーなのでご存じの方も多いと思いますが、紹介しておきます。

2の②でも書きましたが、ブレークポイントを設定してデバッグする際、例えば100回ループが回るとして、99回目で問題が起こるとして、98回ポチポチステップオーバーを回していませんか??

ブレークポイントに特定の条件をつけることも可能ですが、デバッグ中に変数の値を書き換えることで、このような無駄な作業を省くことができます。

サンプルでいいますと、例えば7行目にブレークポイントを設定してデバッグします。

たとえば、このループのデバッグが面倒なので、一気にLogicExceptionを起こす$keyを2にしたいと思った場合、デバッグコンソールで次のようにします。

①編集したい変数を右クリックして、Set Value をクリック

②好きな値を入れます。ここでは、2を入れちゃいます。

③するとすぐ評価されて、LogicExceptionを投げるところに行きます。

これってめちゃくちゃ応用が効いて、いろんなことに使えるんですよね。
普通に関数を開発中に、「この値飛んで来たらどういう処理にしよー?」とか思っている時に、実際にその値を関数に投げるのが呼び出しが深くて面倒な時があります。

そんな時にも使えるし、例えば、Cookieの設定だとか、サーバー変数の設定だとか、特定の環境を再現しないといけないデバッグだとかに、いちいち本物の環境を設定するわけにいかない場合だとかにも使えます。

③Watchを使う

あんましデバッグ時にWatchって使いませんよね(笑)。実は私もです。

ただ、使った方がいいケースがあると思うので、ご紹介しておきます。

今までのサンプルだとあまりに簡単すぎるので、少しだけ複雑なサンプルを作ります。

<?php

class Fruit{

    public string $name;
    public bool $with_milk; // 牛乳とまぜてよいか
    private int $calorie;

    public function __construct(string $name, bool $with_milk, int $calorie){

        $this->name = $name;
        $this->with_milk = $with_milk;
        $this->calorie = $calorie;

    }

    function mixWithMilk():bool{

        if($this->with_milk){

            $this->name = $this->name.'みるく';
            $this->calorie = $this->calorie + 100;
            return true;

        }else{

            return false;

        }

    }

    /**
     * 一日の消費カロリーの何分の1かを表示
     * @return float|int
     */
    function getCalorieOfOneDay(){

        return $this->calorie/3000;

    }

}

$apple = new Fruit('りんご', false, 50);
$strawberry = new Fruit('いちご', true, 31);
$melon = new Fruit('メロン', false, 70);
$banana = new Fruit('バナナ', true, 65);

$fruits = [$apple, $strawberry, $melon, $banana];

foreach ($fruits as $key => $fruit){

    print $fruit->name;
    print "<br>";

    $result = $fruit->mixWithMilk();

    if($result){

        print "牛乳とまぜたら". $fruit->name. "になったよ";

    }else{

        print "牛乳とまぜたらダメー!";

    }

    print "<br>";
    print "-------------------------";
    print "<br>";

}

フルーツの配列がクラスになりました。フルーツがいくつかあって、牛乳とまぜると名称が変わり、カロリーもちょっと変わる、というプログラムです。(カロリーについては全くのデタラメです。)

実行すると、結果は下記のようになります。

ここで、このFruitというオブジェクトの
getCalorieOfOneDay()
というメソッドは実行されていないのですが、実行したらどうなるかをシミュレートできます。それがWatchです。

①57行目にブレークポイントを設定しておきます。

メロン食べたい。

②デバッグを実行します。

③デバッガーウィンドウのコンソールの一番右端の+ボタンをクリックします。

New Watchと出ると思うんですが、そこで
$fruit->getCalorieOfOneDay()
と入力します。

すると、ステップ実行により、変化する

$fruit->getCalorieOfOneDay()
の値を見ることができます。

「え?それで何が嬉しいんですか??Watchって何に役立つんですかー?!」

と言いたくなるかもしれません。

しかし、この機能も可能性は無限大。

使うケース①

例えば このプログラムで言えば、一日の総消費量に対するフルーツミックスジュースの割合、つまりgetCalorieOfOneDay()が0.03を超えたときに発生するバグがあったとします。

しかし、このプログラムのように
mixWithMilk()
みたいな関数でプロパティの値が加工されていると、プロパティの値がどこで変わっているのかトンとわからないときがあります。

その場合に使えます。 ずっと見ているのはだるい場合はWatchに式を入れることができますので、

$fruit->getCalorieOfOneDay()>0.03

というWatchを追加します。

すると、TrueとFalseだけを返してくれるので、より見やすいです。

使うケース②

例えば、人の目で見るのがつらい数字とかがありますよね。
弊社では、配送業向けのODIN リアルタイム配送システムというシステムを開発していますが、0時0分0秒を0として、経過秒数を秒で表すという数字をよく扱います。41200秒は、60×60で割ると11.44で、大体11時半ぐらいだなということがわかります。

ただ、11時半ぐらいと言えばイメージがわきやすいのですが、 41200秒 は正直??って感じですよね。

開発している際のこのわかりやすさって開発効率に大事だと思うんですよ。

なので、そのプロパティを3600で割る数字をWatchしておくと、人間が把握しやすいので、ちょっとだけ開発効率が上がります。

Watchには気楽に式を入れられますので、例えばさっきの

getCalorieOfOneDay()

が小数点で見づらいな、と思えば、×100を入れておくこともできます。

下記のようにさっきWatch式をプラスしたところの空白のスペースに

$fruit->getCalorieOfOneDay()*10


と入力すると、その結果をresult というところに表示してくれます。

ただ、「このresult消えるよ…」ということで、すぐに消えてしまうので、実行の際に見てたい場合は、Watch式を入力したほうがいいです。

以上、そのほかにもデバッガってめちゃくちゃいっぱい機能があります。

ぜひPHPStorm本家のサイトなども見てみてください。

https://pleiades.io/help/phpstorm/examining-suspended-program.html#find-execution-point

PHP コメントで配列の中身の型を定義する

大した話じゃ全然ないんですが、いっつも忘れてしまって、コードの中を漁るはめになっているので、メモっておきます。

何のためにこのコメントがあるかというと、PHPでは、配列の中の変数の型を定義することができません。

なので、コメントに書いておくと親切、ということですね。

    /* @var int[] */
    public array $numbers;

上記のコメントの意味は、$numbers という配列には、数字を入れることになっている、という意味です。

ただし、これはただのコメントなので、なんの強制力もありません。

上記の$numbers に Stringを入れてもエラーを吐いたりはしません…。

しかし、あるとないとで読んだプログラマーさんがわかりやすいので大違いだとは思います。