When I write tests for a model, I put fake model creating inside the setUp method using FactoryMuff.
$this->user = FactoryMuff::create('User', array('password' => '12345678'));
Inside a model there is a saving callback that hashes the password. Callback is triggered (password becomes hashed) until the second test is reached (where password is not hashed). I even checked it with simple var_dump.
public function testFirst() { // $this->user is a good model }
public function testSecond() { // $this->user is a bad model }
Looks like I found an answer, I just had to call User::boot() manually in setUp to register callbacks
Related
I have a class that sets auth middleware in controller, like this:
class MyController extends Controller
{
public function __construct()
{
$this->middleware('auth:api');
}
public function something()
{
dd(Auth::user());
}
}
And a test like this:
class MyControllerTest extends TestCase
{
public function testSomething()
{
$user = factory(User::class)->create();
$this->actingAs($user);
$this->get('api/something');
}
}
The expected output is a dump of the user.
Everything works as expected, both in real application and in feature test.
The problem begins here: If I remove this line: $this->middleware('auth:api'); the output is the dump of user in tests but in real application it gets null. This is a problem as I can't rely on feature test.
With actingAs() Laravel seems to authenticate the user under the hood and then the test pass but the application fails. Is this a bug or there is something I'm missing here?
Using Laravel 7.x
If I understand right - you want test "is route has middleware". Than add to your tests:
public function testAuth()
{
//without acting as
$this->get('api/something')->assertForbidden();
}
With this, you can be you can be sure that Auth::user() is not null.
So I am giving a sample of my controller and web.php file.
controller
{
public function add()
{
//Method called via web.php
}
public function multiply()
{
//how to access this while testing
}
}
web.php
route::get('/add','controller#add');
And now I want to perform unit testing
case1: add $response = $this->get(route('add')); Now it will send a get request when /add is accessed and controller method add will be accessed. And then I can use various assertions to check its functionality.
case2: multiply Here there isn't any route specified, so it wont be able to access controller method.
How can I test my multiply method in such a case
UPDATED ANSWER
So from all the answers and comments, i have understood that in Laravel
Unit Testing - Create a controller instance and then call the method that you want to test.
Feature testing - In this mode of testing, we will be calling the route and testing whether correct method has been hit and it is working as desired.
Thank You!!
You can create the object of controller inside the test file like below.
public function testBasicTest()
{
$object = (new UsersController());
$response = $object->methodName();
$this->assertTrue($response);
}
I am building an application with multiple user roles and actions. I did follow the official laravel doc (https://laravel.com/docs/5.5/middleware#middleware-parameters).
But in my controller's constructor (from where I call the above middleware) I am using Auth facade to get user details. I know how to use Auth facade, I had implemented it on several places inside my application. But when I use it inside the constructor it returns null (in logged in condition - I double checked that).
I implemented it like this, I have to call two controllers(since only registered users can access that page)
public function __construct()
{
$role = Auth::user()->role;
$this->middleware('auth');
$this->middleware('checkRole:$role');
}
PS: I tried to initialize $role variable as protected and outside the constructor , still not working. Any suggestions will be helpful
Thank you.
That's because constructors are created before middlewares,that's why its returning null.
This answer will propably solve your problems: Can't call Auth::user() on controller's constructor
If you are using the same user table for both "front-end" user and "admin" & want to apply condition in admin controller's constructor.
You can use below.
auth()->user()
And in the constructor you can use below code.
public function __construct(){
$this->middleware(function ($request, $next) {
if(auth()->user()->hasRole('frontuser')){
return redirect()->route('home')->withFlashMessage('You are not authorized to access that page.')->withFlashType('warning');
}
return $next($request);
});
}
But I prefer to handle these in separate middleware class instead of writing this in the controllers constructor.
The reason of this question was born from a collaborator's request: I want to know if I can remove the provider. Is mandatory? I want to remove it if I can leave its methods empty.
So, in Symfony providers configuration is mandatory. Also i need to configure at least one Provider. Done! My custom providere is this:
final class CustomListener implements UserProviderInterface
{
public function loadUserByUsername($username)
{
// ...
}
public function refreshUser(UserInterface $user)
{
return $user;
}
public function supportsClass($class)
{
// ...
}
}
I can login. Logout. ... but I am a bit confused. Why an interface want these "useless", at the moment, loadUserByUSername and supportsClass? Useless in the meaning of: I have empty implementation, and it works!!! Work, means that I set session manually with $request->getSession()->set('firefall', $token); and user is authenticated. I can logout users invalidating session.
I am sure that at least, this provider NEEDS that refreshUser return a UserInterface:
public function refreshUser(UserInterface $user)
{
return $user;
}
Because login does not work without this return. But I can leave other methods empty.
I've looked inside tests and in UserProviderInterface method's comments. But nothing. I didnt get if I can:
remove provider;
I am missing something in the documentation;
I am trying to badly use Symfony (it is possible);
I am a Teapot;
...
-
And, .... Why login does not work when I comment this line even if My firewall does not use this provider?
public function refreshUser(UserInterface $user)
{
// return $user;
}
--
I've created this CustomListener just because I've defined
a service as provider. Then I've received this message:
Argument 1 passed to Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider::__construct() must be an instance of Symfony\Component\Security\Core\User\UserProviderInterface,
The user provider tells Symfony where to load the users from, so you need one, but you don't need to create your own unless you have a complex authentication system.
If you're loading the users from the database you can use the default db provider http://symfony.com/doc/current/cookbook/security/entity_provider.html
I have following method in my controller:
public function store()
{
$data=Input::all();
User::create($data);
}
The above code works perfectly. My question is can we run the above method in model without writing in controller? And which is the best approach?
you can try following way
in your model
public function insetUser()
{
$input = Input::all();
User::create($input);
//here instead of User,you can use self like self::create($input);
}
in controller you can
public function store()
{
User::insetUser();
}
If it is in model, how you are going to trigger it?
It is in fact only one line of code
User::create(Input::all());
What it is here is the instance of model User and method create with injected model Input. Of couse you may set (model) User.php:
public function storedata()
{
return $this->create(Input::all());
}
And then run it in your controller:
User::storedata();
But is it better? ;-)
In this circumstance, I don't think you gain much from moving things arounds.
If this is your Controller method:
public function store()
{
$data=Input::all();
User::create($data);
}
then this makes sense. The input data is being handled by the controller method, and is being passed to the create method on your User Model.
If however, there was more logic required before creating a User record, then it'd be perfectly valid to abstract that logic to your User model. But as it stands though, I think your current implementation is appropriate.