問題描述
測試有狀態的 Mojolicious 應用程序 (Testing stateful Mojolicious apps)
我想測試條目的隱藏和取消隱藏。我在 Mojolicious t/basic.t 中進行了以下測試:
my $t = Test::Mojo‑>new('AdminApi');
$t‑>get_ok('/publications/hide/1');
$t‑>get_ok('/read/publications/meta')‑>content_unlike(qr/Paper with id 1:/i);
$t‑>get_ok('/read/publications/meta/1')‑>content_like(qr/Cannot find entry id: 1/i);
$t‑>get_ok('/publications/unhide/1');
$t‑>get_ok('/read/publications/meta')‑>content_like(qr/Paper with id 1: <a href/i);
$t‑>get_ok('/read/publications/meta/1')‑>content_unlike(qr/Cannot find entry id: 1/i);
我的問題是“/publications/hide/1”和“/publications/unhide/1”這兩行不隱藏和取消隱藏入口。條目的狀態保持不變。
如果我在瀏覽器中手動重複這些步驟,一切正常。出於顯而易見的原因,我希望通過測試使其自動化。如何做到這一點?
編輯:調用 '/publications/hide/1' 和 '/publications/unhide/1' 更改數據庫的狀態 ‑ 只是一個簡單的 UPDATE 查詢。此更改適用於整個應用程序 ‑ 適用於所有用戶。但是需要以用戶身份登錄才能隱藏/取消隱藏。問題:如何在測試期間模擬登錄用戶?
參考解法
方法 1:
As you have already said, you need to be logged in to perform the hide
and unhide
action.
my $t = Test::Mojo‑>new('AdminApi');
You are creating a new UserAgent here. The Test::Mojo class inherits from Mojo::UserAgent. It has a cookie_jar
and thus keeps a session alive. You need that to perform this action:
$t‑>get_ok('/publications/hide/1');
But right now you are not logged in. What you need to do is log in the user. Looking at the code in your repository, you actually assert that you are not logged in.
$t‑>get_ok('/')‑>status_is(200)‑>content_like(qr/Please login or register/i);
Before you perform the hide
, you need to log in the user. After digging a bit in your code I found the action and the template to do that, so I know what the request needs to look like.
$t‑>post_ok(
'/do_login' => { Accept => '*/*' },
form => { user => 'admin', pass => 'hunter2' }
);
Now your $t
UserAgent should be logged in and you can do the hide
. Note that get_ok
only checks if there was no transport error. So in fact it would make sense to now check if in fact you are now logged in.
You could do that by introspecting the session in the application, by checking the logfile (you are writing "Login success"
there) or by checking the page for some string that says that the user is logged in. In templates/display/start.html.ep there is a text that welcomes the logged‑in user, so you can use that.
$t‑>post_ok(
'/do_login' => { Accept => '*/*' },
form => { user => 'admin', pass => 'hunter2' }
)‑>text_like(qr/Nice to see you here admin/i);
Because text_like
uses the text‑nodes, the <em>
around the username is not relevant in the test.
Right, now we know you are logged in. Time to switch the thing on and off.
$t‑>get_ok('/publications/hide/1');
Because there is no obvious error thrown for that as far as I can tell, I don't see how to test the success of that. Status code is one way, but there might be something in the content as well that you could test.
To verify the state of the application, you would now call the publication.
$t‑>get_ok('/read/publications/meta')‑>content_unlike(qr/Paper with id 1:/i); $t‑>get_ok('/read/publications/meta/1')‑>content_like(qr/Cannot find entry id: 1/i);
Right. But remember, our $t
is still logged in. Maybe the logged‑in user is allowed to see hidden stuff as well as unhidden stuff. Maybe they are not.
It's probably safer to make a second UserAgent that's not logged in, and check with that one as well.
# check with an unauthorized user
my $t_not_logged_in = Test::Mojo‑>new('AdminApi');
$t_not_logged_in
‑>get_ok('/read/publications/meta')
‑>content_unlike(qr/Paper with id 1:/i);
$t_not_logged_in
‑>get_ok('/read/publications/meta/1')
‑>content_like(qr/Cannot find entry id: 1/i);
Now basically you repeat the same thing by unhiding your content and testing again. Rinse and repeat.
Keep in mind that unless you are using an explicit testing database (which you seem not to do), you cannot be sure that there even is an entry 1. Or what the name of that is. You should use fixtures for the tests. You could, for example, create a fresh instance of the DB using sqlite and work with that.