昨天講到用戶權限這麼重要的功能,當然一定要用自動測試,把這個功能測好測滿呀!
今天來談談用戶權限的測試該怎麼做!
首先,我們來釐清一下我們要測試的項目是什麼,然後針對各個狀況撰寫測試案例。
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
物件,並且有某個 Post
的 user_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()
來對轉址和出現視圖進行斷言!
希望今天各位覺得有收穫,我們明天見!
登入用戶進入 route('posts.store')
時,希望看到的是 view('posts.store')
希望看到的應該是posts.index
?
這段是我寫錯了,這次測試跟 route('posts.store')
沒什麼關係。馬上刪除
想問一下在測試未登入用戶使用修改文章時,跳出了這樣的錯誤碼
1) Tests\Feature\PostControllerTest::testEditWithoutUserShouldRedirectToIndex
Response status code [500] is not a redirect status code.
Failed asserting that false is true.
請問是什麼意思呢?
因為 testEditWithoutUserShouldRedirectToIndex
模擬用戶未登入下,進入到 route('posts.edit', ['post' => $post])
時,出現的是 500 internal server error
而不是我們所預期的跳轉。
原因是上一篇文章內,edit()
的權限檢查,沒有檢查到 $user
是 null
的情況
要改成
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
不會,覺得幫助很多~