Search code examples
phplaravelddd-repositories

Laravel 7 - How do I rebind repository on Validator::extend() for tests?


I have set up a custom validation rule like this:

// Custom created RepositoryProvider.php also registered in app.php 'providers' array.

public $bindings = [
    UserRepository::class => EloquentUserRepository::class,
];

public function boot(UserRepository $userRepository)
{
    Validator::extend('user_email_unique', function($attribute, $value, $parameters) use($userRepository) {
        return !$userRepository->findByEmailAddress($value)->exists();
    });
}

// my test

class SignUpUserActionTest extends TestCase
{
    public function setUp() : void
    {
        parent::setUp();

        $this->app->bind(UserRepository::class, function() {
            return new UserRepositoryMock();
        });
    }
}

In my test I rebind the UserRepository to a mock. It works fine in for the fetching of data, but it maintains the original binding for the validation extension and does not rebind the repository used. They therefore use two different implementations when unit tests are run.

How can I extend the validator so that the automatic resolution is rebound on tests?

Thanks.


Solution

  • Since you do you logic in your RepositoryProvider, this will be instantiated in your parent::setUp() call and thereby fetch your UserRepository before the binding has been mocked. Move the binding before this call and i will assume you will get a different result.

    public function setUp() : void
    {
        $this->app->bind(UserRepository::class, function() {
            return new UserRepositoryMock();
        });
    
        parent::setUp();
    }
    

    EDIT

    Based on your comment, the cause was right the solution was not. Resolve UserRepository in the closure, will most likely make it resolve at a time where your binding is set.

    Validator::extend('user_email_unique', function($attribute, $value, $parameters) {
        $userRepository = resolve(UserRepository::class);
        return !$userRepository->findByEmailAddress($value)->exists();
    });