Fippiyのプログラム学習内容アウトプットBlog

日々の学習内容をアウトプットして振り返りを実施する。

Laravel開発、propertyテーブルをテストする【5】編集エラーテストを実装する

propertyテーブルが関係するテストを実装しています。

編集エラーテストの前にバリデーション未設定について解決を行いましたので、いよいよ編集エラー時のテストを実施していきます。

今回の目的

Propertyテーブルに関連する設定で、想定されるエラーに対しての動作が正常にできていることを確認する

なぜやるか

バリデーションなどエラーに対しての処理が正常に行えている担保をとるため

やりたいこと

  • 想定されるエラーに対してのエラー表示がされていることを確認する
  • リダイレクト処理が正常にできていることを確認する

やったこと

  • 所有書籍のタイトルを削除するとエラーとなること
  • 存在しない所有書籍情報を編集しようとするとエラーとなること
  • 他人の所有情報を編集できないようにする
  • 他人の所有情報を編集しようとするとエラーとなること

実施内容

編集時のエラーテストを実装する

タイトルがない場合

前回の記事でそもそもタイトル編集は行わないといいながら、テストを行っています。

不正な登録としてタイトル情報、bookdata_idが送信されても更新されないことを確認することで、テストを行っています。

# ~/tests/Feature/PropertyTest.php

// 所有書籍情報編集NG、タイトルなし
public function test_propertyControll_ng_notTitleEdit()
{
// property 自動生成 // 関連 user,bookdataも作成
$propertydata = factory(Property::class)->create();
 
// ユーザーログイン
$user = User::first(); // 作成済みユーザー情報取得
$this->actingAs($user); // 選択ユーザーでログイン
$this->assertTrue(Auth::check()); // Auth認証済であることを確認

//// 編集パス
$propertypath = 'property/'.$propertydata->id.'/edit'; // 書籍編集パス
//// 編集
$editpropertydata = [
'bookdata_id' => '',
'_method' => 'PUT',
]; // タイトルなしに編集
$response = $this->from($propertypath)->
 post('property/'.$propertydata->id, $editpropertydata); // 本情報保存
$response->assertSessionHasErrors(['bookdata_id']); // エラーメッセージがあること
$response->assertStatus(302); // リダイレクト
$response->assertRedirect($propertypath); // トップページ表示
$this->assertEquals('bookdata idは必須です。',
session('errors')->first('bookdata_id')); // エラメッセージを確認
}

Propertyファクトリーで、所有書籍と関連する書籍情報・ユーザー情報をまとめて作成し、作成ユーザーでログインしています。

そして、作成されている所有書籍情報の編集ページから送信するpostデータにbookdata_id=>''を指定して、書籍idを削除しているパターンです。

結果として、bookdata_idカラム情報は送信されるのでバリデーションにひっかかり、エラーが返ってきます。

 

propertyテーブルにまだ存在していないidを指定する

propertyテーブルに1件のみ登録した状態で2件目の編集を強制的に行っています。

# ~/tests/Feature/PropertyTest.php

// 所有書籍情報編集NG、未登録id
public function test_propertyControll_ng_notIdEdit()
{
// property 自動生成 // 関連 user,bookdataも作成
$propertydata = factory(Property::class)->create();
 
// ユーザーログイン
$user = User::first(); // 作成済みユーザー情報取得
$this->actingAs($user); // 選択ユーザーでログイン
$this->assertTrue(Auth::check()); // Auth認証済であることを確認

// 編集パス
$propertypath = 'property/2/edit'; // 書籍編集パス(存在しないID)

// アクセス不可
$response = $this->get($propertypath); // ページにアクセス
$response->assertStatus(500); // 500ステータスであること
}

ファクトリーにより1件の情報を作成しています。

この時点ではpropertyテーブルのid=1に対して、user_id=1,bookdata_id=1というデータのみが存在する状態です。

この状態でpropertyテーブルのid=2を編集しようとしています。

当然、まだ存在しないテーブルですので編集できるわけがなく、エラーとして帰ってきます。

 

他人が所有している書籍情報を強制的に書き換える

自分の所有書籍を編集するのが基本ですが、プログラム上で強制的に他人の所有書籍を変更させてみたところ、変更できてしまいました。

propertyテーブル,user_id=1,bookdata_id=1というデータがあったとして、user_id=2の人がログインした状態でこのレコードの情報を無理矢理変更しようというものです。

テストとしてuser_id=2でログインした状態を作り、propertyレコード宛てにpost送信すると更新できました。

 

と、この場合、更新できては困るので、先にこの対策を行います。

# ~/app/Http/Controllers/PropertyController.php

public function update(Request $request, $id)
{
// バリデーションチェック
$createPropertyRules = Property::createPropertyRules();
$this->validate($request, $createPropertyRules);
// 対象レコード取得
$property = Property::find($id);
// 本人認証の上、更新処理
if ($property['user_id'] == Auth::user()->id){
// リクエストデータ受取
$form = $request->all();
// フォームトークン削除
unset($form['_token']);
// レコードアップデート
$property->fill($form)->save();
}
return redirect('/property');
}

ifによって取得したpropertyレコード内のuser_idとログインユーザーのidを照合し、本人であれば編集する形に変更としました。

本来フォーム上からこのような状態のデータは送信されない設計となっていますが、テスト上で通っていた問題点は解決しておくべきなので、処理を追加しています。

 

対策が完了したので、改めて他人の所有書籍編集に対してテストを実施します。

# ~/tests/Feature/PropertyTest.php

// 複数ユーザーデータ有りで他人データ編集
public function test_propertySomeControll_ng_otherUserDataEdit()
{
// 設定
$usernumber = 2;// ユーザー数
$booknumber = 10;// 所有書籍数

// ユーザー情報
factory(User::class, $usernumber)->create(); // 複数ユーザー作成
$user = User::find(1); // ユーザー情報取得
$this->actingAs($user); // 選択ユーザーでログイン
$this->assertTrue(Auth::check()); // Auth認証済であることを確認

// 所有書籍情報登録
// 複数ユーザー分の所有書籍情報
for ($usercount = 1; $usercount <= $usernumber; $usercount++) {
// 各ユーザーに対して複数書籍所持情報を作成
for ($i = 1; $i <= $booknumber; $i++) {
$propertydata = factory(Property::class)->create([
'user_id' => $usercount,
]);
}
}
//// 編集パス
$propertypath = 'property/11/edit'; // 書籍編集パス
//// 登録
$editpropertydata = [
'number' => 11,
'_method' => 'PUT',
]; // タイトルを編集
$response = $this->from($propertypath)->post('property/11', $editpropertydata);
 // 本情報保存
$response->assertStatus(302); // リダイレクト
$response->assertRedirect('property'); // indexへリダイレクト

// DBが変更されていないこと
$savebook = Property::find(11);
$this->assertDatabaseHas('properties', [
'id' => $savebook->id,
'number' => $savebook->number,
]); //DBに配列で指定した情報が残っていること
}

2人のユーザーを準備し、それぞれ10件の書籍を所有している状態としました。

この時点でユーザー1がbookdata_id=1〜10、ユーザー2がbookdata_id_11=20を所有している状態です。

ユーザー1でログインしておき、ユーザー2のbookdata_id=11を強制的に編集しています。

本来であれば、ユーザーが異なるのでそもそもproperty/11にはアクセスできないはずですが、それでもユーザーが異なる場合は編集できないことを確認しています。

最後にDB上でも変更されていないことを確認して、他人の所有書籍が変更できていないことを確認しました。 

 

 

以上で、編集時のエラーテストは終了です。

残るは削除時のエラーテストを実施します。