iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 23
2
Modern Web

Laravel 6.0 初體驗!怎麼用最新的 laravel 架網站!系列 第 23

[Day 23] 談用戶權限,怎麼能不談測試呢?

  • 分享至 

  • xImage
  •  

昨天講到用戶權限這麼重要的功能,當然一定要用自動測試,把這個功能測好測滿呀!

今天來談談用戶權限的測試該怎麼做!

新增測試案例

首先,我們來釐清一下我們要測試的項目是什麼,然後針對各個狀況撰寫測試案例。

針對 index 的測試

有關顯示畫面的判斷,我們可以用 assertViewIs() 這個函式進行斷言。

我們先建立一個 testIndex() 來牛刀小試一下

public function testIndex()
{
    $response = $this->get(route('posts.index'));
    $response->assertViewIs('posts.index');
}

如果順利的話,這個測試案例是可以通過的,代表當我們進入 route('posts.index') 時,看到的一定會是 posts.index 這個 view。

針對 create 的測試

未登入用戶

如果是未登入的用戶,嘗試連線到 route('posts.create') 的話,應該會被重新導向到 route('login') 的。

所以,我們利用 assertRedirect() 這個函式,來對重新導向的位置進行斷言。

public function testCreateWithoutUserShouldRedirectToLogin()
{
    $response = $this->get(route('posts.create'));
    $response->assertRedirect(route('login'));
}

已登入用戶

已登入用戶就比較棘手一點點了,畢竟我們似乎不太可能在自動測試的時候,先幫用戶註冊登入過後,再進行後續的測試。

幸好, Laravel 在這一方面,一樣提供了很方便的函式,供我們在自動測試的階段模擬用戶登入。

我們先利用 Laravel 提供的 factory() 函式,幫我們快速建立一個新的 User 物件

$user = factory(User::class)->create();

然後,利用 actingAs() 這個函式,我們就可以在測試時模擬為 $user 這個使用者,來進行對 route('posts.create') 的存取。

組合起來就是

public function testCreateWithUserShouldShowCreatePage()
{
    $user = factory(User::class)->create();
    $response = $this->actingAs($user)->get(route('posts.create'));
    $response->assertViewIs('posts.create');
}

正確操作的話,這個測試案例應該要可以順利通過。

針對 update 的測試

未登入用戶

針對未登入用戶的做法跟之前差不多,只是需要多加一個 Post 物件而已

public function testEditWithoutUserShouldRedirectToIndex()
{
    $post = new Post;
    $post->content = '';
    $post->subject_id = 0;
    $post->user_id = 0;
    $post->save();
    $response = $this->get(route('posts.edit', ['post' => $post]));
    $response->assertRedirect(route('posts.index'));
}

已登入用戶

已登入用戶的部分就比較麻煩一點點了,因為我們還必須針對用戶是不是該文章的作者,分別作出不同行為判斷

用戶正確

如果我們先用 factory() 建立了一個 User 物件,並且有某個 Postuser_id 就是該物件的 id 的話,要是該用戶存取 route('posts.edit', ['post' => $post]) 的話,應該是可以正常看到 posts.edit 這個 view 的。

public function testEditWithCorrectUserShouldShowPostIndex()
{
    $user = factory(User::class)->create();
    $post = new Post;
    $post->content = '';
    $post->subject_id = 0;
    $post->user_id = $user->id;
    $post->save();
    $response = $this->actingAs($user)
        ->get(route('posts.edit', ['post' => $post]));
    $response->assertViewIs('posts.edit');
}
用戶不正確

我們利用 factory() 建立兩個 User 物件,拿第一個 User 建立文章,第二個 User 存取文章。

順利的話,應該會被導回 route('posts.index')

public function testEditWithIncorrectUserShouldRedirectToIndex()
{
    $users = factory(User::class, 2)->create();
    $post = new Post;
    $post->content = '';
    $post->subject_id = 0;
    $post->user_id = $users[0]->id;
    $post->save();
    $response = $this->actingAs($users[1])
        ->get(route('posts.edit', ['post' => $post]));
    $response->assertRedirect(route('posts.index'));
}

到這裡,我們針對之前所設置的條件,也就是有關新增和編輯的用戶權限設置,就告一段落囉!


小小總結一下我們學到了些什麼。

今天我們學到了怎麼利用 factory() 函式在測試時建立物件,怎麼利用 actingAs() 來模擬用戶存取的行為,還學到用 assertRedirect()assertViewIs() 來對轉址和出現視圖進行斷言!

希望今天各位覺得有收穫,我們明天見!


上一篇
[Day 22] 實作用戶權限!談 Laravel Policy
下一篇
[Day 24] 紀錄網站的問題!談寫 Log
系列文
Laravel 6.0 初體驗!怎麼用最新的 laravel 架網站!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

0
Nighteye1228
iT邦新手 5 級 ‧ 2019-09-26 16:15:00

登入用戶進入 route('posts.store') 時,希望看到的是 view('posts.store')


希望看到的應該是posts.index

ReccaChao iT邦研究生 5 級 ‧ 2019-09-26 16:28:09 檢舉

這段是我寫錯了,這次測試跟 route('posts.store') 沒什麼關係。馬上刪除

0
Nighteye1228
iT邦新手 5 級 ‧ 2019-09-26 16:38:54

想問一下在測試未登入用戶使用修改文章時,跳出了這樣的錯誤碼

1) Tests\Feature\PostControllerTest::testEditWithoutUserShouldRedirectToIndex
Response status code [500] is not a redirect status code.
Failed asserting that false is true.

請問是什麼意思呢?

ReccaChao iT邦研究生 5 級 ‧ 2019-09-26 16:46:02 檢舉

因為 testEditWithoutUserShouldRedirectToIndex 模擬用戶未登入下,進入到 route('posts.edit', ['post' => $post]) 時,出現的是 500 internal server error 而不是我們所預期的跳轉。

原因是上一篇文章內,edit() 的權限檢查,沒有檢查到 $usernull 的情況

要改成

public function edit(Post $post)
{
    $user = Auth::user();
    if(is_null($user) || $user->cant('update', $post)){
        return redirect(route('posts.index'));
    }
    return view('posts.edit', ['post' => $post]);
}

昨天的文章也改正了,感謝你的回應,才發現昨天文章的問題XD

不會,覺得幫助很多~

我要留言

立即登入留言