Testing Laravel Socialite

I recently worked on a project using Laravel Socialite, which was great to use. When it came time to write an automated test however, things were a little less clear.

Written in September 2022, so some of this may be out of date.

I recently worked on a project using Laravel Socialite. The application needed to detect unauthorised requests and redirect users to Microsoft Azure/365 for authentication. On success, the user would return to the application and be logged in.

Socialite is perfect for this because it works in the “Laravel way”, meaning it's easy to test, and not tightly coupled to a single implementation. There are also loads of easy to use community created drivers to support different integrations i.e. Google, Microsoft, GitHub etc. When it came time to write an automated test however, things were a little less clear. 

Let’s run through how I tested my application when using Socialite.

Create your test

Once you’ve pulled in Socialite and got everything setup, the first step is to create your test file so that you can run your test. You can do this using Laravel’s artisan make:test helper if you wish. 

Once this is ready we need to think about how we’re going to test Socialite. With the use case outlined in the intro above, we’re specifically going to test the success request that comes back from Microsoft. 

We’re not testing Socialite or its drivers directly, because this has been taken care of for us already. The people that look after Socialite and its supporting packages will test these so we don’t need to. What we are testing is our application’s use of Socialite… So we’re going to assume Socialite and the driver package is working correctly, which is a fair assumption because it’s well used and respected in the Laravel community.

Mocking Socialite

In our test we don’t actually want to go off to Microsoft and try to auth etc. Not only is this probably impossible, it’s also not something we need to be concerned with. Remember we are testing our usage of Socialite and have to assume that the package and integration works as it should.

In our controller method, to get the authed user in the success response is very simple:

PHP

There are a few things going on under the hood though when calling the above functions. Let’s break down these moving parts:

  • There’s the Socialite facade itself, which is ready for tests out of the box and is where you call the driver method.

  • There’s the Socialite Provider i.e. which 3rd party are you working with. This is denoted by the string passed to the driver method above - in this case ‘azure’.

  • And there’s the User which is the user object we get back from the provider.

So we have this sort of flow in order to get to a user:

Plain text

We need to mock all three objects above, and pass them between each other in our test. Thanks to dependency injection, and how easy Laravel makes testing, this is fairly straightforward to do.

Mocking the user

Let’s begin with the User. Remember this is the user object we expect Socialite to give us on success. We can mock this like below:

PHP

What we’re saying here is that when Laravel tries to create an object from a class implementing the  Laravel\Socialite\Contracts\User don’t actually create one, but pretend that you have and this is the object to give back for it.

In my application I am using the Azure driver from Socialite Providers. As such, the user object created is an OAuth2 user from that package. I recommend investigating and understanding how your particular driver works, if anything just for your own piece of mind.

Mocking the provider

We now have a mocked user ready to go. Next we're going to mock the provider itself. If we look back to our method calls in our controller again, the provider is returned from this method:

PHP

We can mock the provider returned from this method like below:

PHP

Notice how we pass the previously mocked and created $user into this mock so that it can return it. 

Similarly to the User mock above, what we’re saying here is: when Laravel tries to make a class that is implementing the Socialite provider contract, don’t actually make one. Pretend that you have, and expect a method call to ->user() where you should return our mocked $user object.

Mocking the Socialite facade

The final part of this is the Socialite facade itself. Looking back at our controller method we’re calling ->driver(‘azure’) on this facade.

Facades in Laravel are really easy to test out of the box. You can test the facade like below:

PHP

What we’re saying here is that on the Socialite facade we’re expecting the method “driver” to be called, with a string argument passed to it (‘azure’) and for this to return our previously mocked $provider. The above mocking methods called on a facade setup for testing enables this to just work as a mock out of the box. How simple is that!

Finishing up

At this point in our test we can go about our normal business. So you will likely make a test call to your request endpoint where the controller method is called. You can then run whatever assertions you need to, depending on your application, but you will now have a fully mocked Socialite flow.

Hopefully this has cleared up how to write an automated test when using Socialite, and how it is fairly straightforward once you understand all the moving parts. It also highlights the power of Laravel and how easy it makes it to test your applications, especially the most complex aspects.

Go forth now and test, test, test! 🚀