I'm trying to make my AuthController
testable. I start by injecting the Auth class so I can mock it in my test:
public function __construct(Auth $auth)
{
$this->auth = $auth;
}
Then I use the injected class later when I check if the login succeeded:
public function postLogin()
{
// instead of Auth::attempt(Input::all())
if ($this->auth->attempt(Input::all()) {
return 'you are logged in!';
} else {
return 'login failed!';
}
}
When I submit my login form I get an error that the Auth::attempt
method is not defined:
FatalErrorException: Error: Call to undefined method Illuminate\Support\Facades\Auth::attempt() ...
What am I doing wrong? I saw this exact technique used in models, but apparently it's not working for the Auth class.
Well, you might be doing it wrong here...
tl;dr
Define a mock Auth Adapter and configure Auth to use that in tests. Using Auth's static methods in Controllers is just fine.
Why this works...
The Auth package implements a Driver (aka Adapter) pattern with the Auth class acting as the dependency manager and singleton interface for the whole package. Instead of trying to inject a mock Auth instance into your controller, you should implement a mock Auth Adapter (like the default Eloquent and Fluent adapters). Also try configuring your Auth to use the In-Memory Adapter while in tests. From the manual page (for the lazy) with emphasis mine:
In-Memory Sessions
The "memory" session driver just uses a simple array to store your session data for the current request. This driver is perfect for unit testing your application since nothing is written to disk. It shouldn't ever be used as a "real" session driver.
The memory adapter is just an in-memory array, and since your tests are sharing threads with your System Under Test (SUT), you can freely inspect the content of the session from within your test code to verify side-effects of authentication and post-conditions.
When you use Auth
class you can mock it using:
Auth::shouldReceive('attempt')->once()->andReturn(true)
This way your facade
would be mocked!
Hope it helps!
That’s awesome, we can move to class TestCase for all test case and we can give a name, like this:
public function loginWithFakeUser()
{
$user = new User([
'id' => 1,
'name' => 'yish'
]);
$this->be($user);
}
When we need to the authenticated user we can call loginWithFakeUser to pretend user.
This will definitely work.
Thanks,