Thoughts from anyone?
Auth Testing
Thoughts on what I'm doing in this test class.
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class AuthTest extends TestCase
{
use DatabaseTransactions;
protected $user;
protected $password = 'testpass123';
public function get_user()
{
if ($this->user) return;
$this->user = factory(App\User::class)->create([
'email' => 'john@example.com',
'password' => bcrypt($this->password),
]);
}
/** @test */
public function a_user_can_successfully_log_in()
{
$this->get_user();
$this->visit(route('login'));
$this->type($this->user->email, 'email');
$this->type($this->password, 'password');
$this->press('Login');
$this->seePageIs(route('dashboard'));
}
/** @test */
public function a_user_receives_errors_for_wrong_login_credentials()
{
$this->visit(route('login'));
$this->type($this->user->email, 'email');
$this->type('invalid-password', 'password');
$this->press('Login');
$this->see('These credentials do not match our records.');
}
/** @test */
public function a_user_is_redirected_to_dashboard_if_logged_in_and_tries_to_access_login_page()
{
$this->get_user();
$this->actingAs($this->user);
$this->visit(route('login'));
$this->seePageIs(route('dashboard'));
}
/** @test */
public function a_user_is_redirected_to_login_page_if_not_logged_in_and_trying_to_access_dashboard()
{
$this->get_user();
$this->visit(route('dashboard'));
$this->seePageIs(route('login'));
}
}
What sort of thoughts are you looking for? Here are my initial ones, without looking into the details of each test;
- code seems cleanly written.
- some people may chain the testing functions as opposed to calling them from $this on each line.
- test names seem nice an descriptive
As to whether the above provides you any value is difficult to say. It's only really testing boilerplate code and no real business logic. However, it seems like a neat start.
@ifpingram or anyone else. When I run the test I get the following.
PHPUnit 4.8.21 by Sebastian Bergmann and contributors.
.EFF
Time: 756 ms, Memory: 18.25Mb
There was 1 error:
1) AuthTest::a_user_receives_errors_for_wrong_login_credentials
ErrorException: Trying to get property of non-object
/Users/me/Projects/app/tests/unit/AuthTest.php:39
--
There were 2 failures:
1) AuthTest::a_user_is_redirected_to_dashboard_if_logged_in_and_tries_to_access_login_page
Did not land on expected page [http://localhost/app/dashboard].
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'http://localhost/app/dashboard'
+'http://localhost'
/Users/me/Projects/app/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/InteractsWithPages.php:142
/Users/me/Projects/app/tests/unit/AuthTest.php:53
2) AuthTest::a_user_is_redirected_to_login_page_if_not_logged_in_and_trying_to_access_dashboard
Did not land on expected page [http://localhost/app/login].
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'http://localhost/app/login'
+'http://localhost/app/dashboard'
/Users/me/Projects/app/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/InteractsWithPages.php:142
/Users/me/Projects/app/tests/unit/AuthTest.php:61
FAILURES!
Tests: 4, Assertions: 13, Errors: 1, Failures: 2
Anyone?
Well..
a_user_receives_errors_for_wrong_login_credentials is not calling $this->get_user();... but it's trying to reference it with $this->user->email
I would change the top get_user function from
public function get_user()
{
if ($this->user) return;
$this->user = factory(App\User::class)->create([
'email' => 'john@example.com',
'password' => bcrypt($this->password),
]);
}
to
public function setUp()
{
parent::setup();
$this->user = factory(App\User::class)->create([
'email' => 'john@example.com',
'password' => bcrypt($this->password),
]);
}
and then remove all the $this->get_user() in the tests.
@xtremer360
$this->user is null in a_user_receives_errors_for_wrong_login_credentials so you are seeing the Trying to get property of non-object error. It's value set in the test a_user_can_successfully_log_in before is not preserved when a test ends.
There are a couple options, e.g.
- Call
$this->get_user();at the beginning of any test where you need a user. But keep in mind that it won't be the same user object. I would not recommend doing this. - Use a method annotated with
/** @before */to set up a user, see fixtures. - If you really need the same user object in multiple tests you can use test dependencies.
@skliche Thanks for the reply. It doesn't have to be the same user for all the tests. So which of the first two do you think would be a better option for this scenario?
@nfauchelle If I make an attempt at your way then all of my tests time out at 2.01 minutes.
@xtremer360 If you only need the user object in a few of the tests within that test class use $this->get_user();. It's simple, easy and does the job - but you have to keep in mind to call it.
If you need a user object in all/almost all of the tests within that test class, go with the annotated method:
/** @before */
public function setupUserObjectBeforeAnyTest() {
$this->user = factory(App\User::class)->create([
'email' => 'john@example.com',
'password' => bcrypt($this->password),
]);
}
But I'd recommend trying the annotated method anyway. It's something you most probably need for more complex tests in the future.
@skliche What's the difference between doing that annotated way and doing the public function setUp in the test class?
@xtremer360 This was you can declare multiple functions that will be ran before any other test. Let's say you need to create a lot of objects before you can test, you can imagine that your setUp method would be really big. This way you don't have to do that ;)
@bobbybouwmann Thanks for clarifying that for me. However if I run my unit testsuite I get 4 errors and they are all because the operation timed out after 2.01 minutes still.
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class AuthTest extends TestCase
{
use DatabaseTransactions;
protected $user;
protected $password = 'testpass123';
/** @before */
public function setupUserObjectBeforeAnyTest()
{
$this->user = factory(App\User::class)->create([
'email' => 'john@example.com',
'password' => bcrypt($this->password),
]);
}
/** @test */
public function a_user_can_successfully_log_in()
{
$this->visit(route('login'));
$this->type($this->user->email, 'email');
$this->type($this->password, 'password');
$this->press('Login');
$this->seePageIs(route('dashboard'));
}
/** @test */
public function a_user_receives_errors_for_wrong_login_credentials()
{
$this->visit(route('login'));
$this->type($this->user->email, 'email');
$this->type('invalid-password', 'password');
$this->press('Login');
$this->see('These credentials do not match our records.');
}
/** @test */
public function a_user_is_redirected_to_dashboard_if_logged_in_and_tries_to_access_login_page()
{
$this->actingAs($this->user);
$this->visit(route('login'));
$this->seePageIs(route('dashboard'));
}
/** @test */
public function a_user_is_redirected_to_login_page_if_not_logged_in_and_trying_to_access_dashboard()
{
$this->visit(route('dashboard'));
$this->seePageIs(route('login'));
}
}
Are you sure your database and stuff is working and setup correctly? The tests seem fine to me..
Yes. I've ran tests before I started doing these changes and it works fine.
I tried to run these tests and this one
/** @test */
public function a_user_is_redirected_to_dashboard_if_logged_in_and_tries_to_access_login_page()
{
$this->actingAs($this->user);
$this->visit(route('login'));
$this->seePageIs(route('dashboard'));
}
is not running. When I commented it out, all other tests are passing
@xtremer360 Run the tests with phpunit --debug. It should output what tests are run in what sequence and you should be able to see what test is causing the lockup. Additionally you could call each test separately like phpunit --filter name_of_test_method.
@skliche I performed the suggested commands by running phpunit --debug and saw the results and it gave me the same error that I received before with the connection timing out.
@bobbybouwmann Would you know why?
@xtremer360 Show us the exact error you get. Do you get that error even when you run just a single test using --filter?
@skliche This is what is returned when I run phpunit.
Me-iMac:backstage me$ phpunit
PHPUnit 4.8.21 by Sebastian Bergmann and contributors.
EEEE
Time: 2.01 minutes, Memory: 14.25Mb
There were 4 errors:
1) AuthTest::a_user_can_successfully_log_in
PDOException: SQLSTATE[HY000] [2002] Operation timed out
/Users/me/Projects/app/vendor/laravel/framework/src/Illuminate/Database/Connectors/Connector.php:55
/Users/me/Projects/app/vendor/laravel/framework/src/Illuminate/Database/Connectors/MySqlConnector.php:22
/Users/me/Projects/app/bootstrap/cache/compiled.php:11423
/Users/me/Projects/app/bootstrap/cache/compiled.php:11419
/Users/me/Projects/app/bootstrap/cache/compiled.php:11326
/Users/me/Projects/app/bootstrap/cache/compiled.php:11281
/Users/me/Projects/app/bootstrap/cache/compiled.php:11157
/Users/me/Projects/app/bootstrap/cache/compiled.php:11144
/Users/me/Projects/app/bootstrap/cache/compiled.php:10568
/Users/me/Projects/app/bootstrap/cache/compiled.php:10559
/Users/me/Projects/app/bootstrap/cache/compiled.php:10391
/Users/me/Projects/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:86
/Users/me/Projects/app/tests/unit/AuthTest.php:18
2) AuthTest::a_user_receives_errors_for_wrong_login_credentials
PDOException: SQLSTATE[HY000] [2002] Operation timed out
/Users/me/Projects/app/vendor/laravel/framework/src/Illuminate/Database/Connectors/Connector.php:55
/Users/me/Projects/app/vendor/laravel/framework/src/Illuminate/Database/Connectors/MySqlConnector.php:22
/Users/me/Projects/app/bootstrap/cache/compiled.php:11423
/Users/me/Projects/app/bootstrap/cache/compiled.php:11419
/Users/me/Projects/app/bootstrap/cache/compiled.php:11326
/Users/me/Projects/app/bootstrap/cache/compiled.php:11281
/Users/me/Projects/app/bootstrap/cache/compiled.php:11157
/Users/me/Projects/app/bootstrap/cache/compiled.php:11144
/Users/me/Projects/app/bootstrap/cache/compiled.php:10568
/Users/me/Projects/app/bootstrap/cache/compiled.php:10559
/Users/me/Projects/app/bootstrap/cache/compiled.php:10391
/Users/me/Projects/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:86
/Users/me/Projects/app/tests/unit/AuthTest.php:18
3) AuthTest::a_user_is_redirected_to_dashboard_if_logged_in_and_tries_to_access_login_page
PDOException: SQLSTATE[HY000] [2002] Operation timed out
/Users/me/Projects/app/vendor/laravel/framework/src/Illuminate/Database/Connectors/Connector.php:55
/Users/me/Projects/app/vendor/laravel/framework/src/Illuminate/Database/Connectors/MySqlConnector.php:22
/Users/me/Projects/app/bootstrap/cache/compiled.php:11423
/Users/me/Projects/app/bootstrap/cache/compiled.php:11419
/Users/me/Projects/app/bootstrap/cache/compiled.php:11326
/Users/me/Projects/app/bootstrap/cache/compiled.php:11281
/Users/me/Projects/app/bootstrap/cache/compiled.php:11157
/Users/me/Projects/app/bootstrap/cache/compiled.php:11144
/Users/me/Projects/app/bootstrap/cache/compiled.php:10568
/Users/me/Projects/app/bootstrap/cache/compiled.php:10559
/Users/me/Projects/app/bootstrap/cache/compiled.php:10391
/Users/me/Projects/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:86
/Users/me/Projects/app/tests/unit/AuthTest.php:18
4) AuthTest::a_user_is_redirected_to_login_page_if_not_logged_in_and_trying_to_access_dashboard
PDOException: SQLSTATE[HY000] [2002] Operation timed out
/Users/me/Projects/app/vendor/laravel/framework/src/Illuminate/Database/Connectors/Connector.php:55
/Users/me/Projects/app/vendor/laravel/framework/src/Illuminate/Database/Connectors/MySqlConnector.php:22
/Users/me/Projects/app/bootstrap/cache/compiled.php:11423
/Users/me/Projects/app/bootstrap/cache/compiled.php:11419
/Users/me/Projects/app/bootstrap/cache/compiled.php:11326
/Users/me/Projects/app/bootstrap/cache/compiled.php:11281
/Users/me/Projects/app/bootstrap/cache/compiled.php:11157
/Users/me/Projects/app/bootstrap/cache/compiled.php:11144
/Users/me/Projects/app/bootstrap/cache/compiled.php:10568
/Users/me/Projects/app/bootstrap/cache/compiled.php:10559
/Users/me/Projects/app/bootstrap/cache/compiled.php:10391
/Users/me/Projects/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:86
/Users/me/Projects/app/tests/unit/AuthTest.php:18
FAILURES!
Tests: 4, Assertions: 0, Errors: 4.
@xtremer360 Check if your database connection variables are correct and the mysql or whatever it is up and running. Especially check the host and unix_socket
Without the test everything else works.
@xtremer360 Do you have a separate test database connection?
I do. Let me show you what that looks like.
'mysql_testing' => [
'driver' => 'mysql',
'host' => env('TESTING_DB_HOST', 'localhost'),
'database' => env('TESTING_DB_DATABASE', 'forge'),
'username' => env('TESTING_DB_USERNAME', 'forge'),
'password' => env('TESTING_DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
TESTING_DB_HOST=192.168.10.10
TESTING_DB_DATABASE=app_testing
TESTING_DB_USERNAME=homestead
TESTING_DB_PASSWORD=secret
Is your host IP address correct? Also use this:
unix_socket = /var/run/mysqld/mysqld.sock
Why do I need to use that. I've never seen people use that?
Sometimes, MySQL needs to be specified about the socket being used for the connection. Are you using MAMP on Mac?
I do not because Laracasts has taught me to use homestead and not use Mamp.
Is there any other suggestions?
@xtremer360 Does the problem still exist if you reduce the test to the following?
class ExampleTest extends TestCase {
protected $user;
protected $password = "test";
/** @before */
public function setupUserObjectBeforeAnyTest() {
// need to set up database transactions support manually first, otherwise the user will be created before database transactions are set up by the usual trait
$this->app->make('db')->beginTransaction();
$this->beforeApplicationDestroyed(function () {
$this->app->make('db')->rollBack();
});
$this->user = factory(App\User::class)->create([
'email' => 'john@example.com',
'password' => bcrypt($this->password),
]);
}
public function a_user_is_redirected_to_dashboard_if_logged_in_and_tries_to_access_login_page() {
$this->actingAs($this->user);
$this->visit(route('login'));
$this->seePageIs(route('dashboard'));
}
}
That works for me. If this still runs into a timeout on your system then something's definitely wrong with your database connection.
If I create that code snippet as a new test file and put it inside of my unit test folder as the only test file and do the following it shows what I receive.
Me-iMac:app me$ phpunit --testsuite unit
PHPUnit 4.8.21 by Sebastian Bergmann and contributors.
F
Time: 76 ms, Memory: 10.50Mb
There was 1 failure:
1) Warning
No tests found in class "ExampleTest".
FAILURES!
Tests: 1, Assertions: 0, Failures: 1.
Does anyone know why after my last post?
Please or to participate in this conversation.