jan_zikmund's avatar

Test function using 3rd party OAuth2

Hi, is there any convenient way to write a PHPUnit test for a functionality, which consumes 3rd party API authenticated with OAuth2? I don't need to test the OAuth2 flow itself, I just have one route which connects to their API, gathers some data and shows them, and this route I want to test.

Obviously, when I am not authenticated, no data is gathered, so the test fails. But here is the trouble - how do I simply authenticate in the test to access the data? So far I have tried:

  1. sending the test to my authentication URL first - here I receive the Header: redirect which tries to send me to 3rd party to confirm the access to resources. Here the test ends as it doesn't know what to do next.

  2. Somehow obtaining authentication keys from my live environment - in my live app I store them using Cache:: facade, and I would be ok just querying these for the test, but I struggle receiving them within the scope of the test environment. I even tried calling shell_exec and somehow receive them from php artisan tinker --execute="dump(Cache::get('access_token'))" , but to no success.

Thanks for any pointers.

0 likes
6 replies
martinbean's avatar

@jan_zikmund You shouldn’t be making any network calls in tests. And especially not to anything in a live or production environment!

Your code should be wrapped in some sort of class where you can mock the authentication or network call and test that your app works if it receives the right data.

If you make actual network calls in your tests then that’s going to make your test suite useless without a network connection. It also makes you’ll get failures if the service you’re hitting is down, or will slow your test suite down if it’s running slow.

jan_zikmund's avatar

Hi @martinbean ,

thanks for the insight, but just to get back to my original question, you mean that writing test for obtaining OAuth data isn't possible, is that correct?

As even though I see your point, I feel like these tests have already done quite a good job and I want to keep them this way. When I run them, I am just sure that everything works including the data from APIs. If the 3rd party changes something and suddenly returns something I don't expect, or not return anything when they change authentication etc., I don't care whose fault it is, I just know I have to update my code accordingly and the tests will tell me. Assuming their API gives me something and base it on that just isn't good enough for me, because if the API doesn't give it, I am screwed and my test won't find out. And speed is not much of a concern either, the few seconds extra I can easily live with. Btw what is the point of running the tests offline?

1 like
SereySoksan's avatar

Hi @jan_zikmund

I know it's been a while with this conversation. I have recently started to work with Unit Testing and have felt into the same scenario as you did. Would you mind to share what is your solution into this problem? I'm really for your help.

jan_zikmund's avatar

@SereySoksan Hi, IIRC I don't think I found a reliable way. To receive the data you need to provide the keys, and as long as you have them (perhaps from your previous live session), you're ok. But at the moment the server requests reauthentication, you are screwed, because this has to be done from the browser - you are taken to their website where you confirm your password, then potentially some 2FA validation, often there is a ReCaptcha or other automation protection and you just cannot pass this in a unit test.

Now I would probably just handle this in the application itself - make sure the system is stable if the returned values fail, and make sure I get notification about the problem - either through something like Bugsnag, or just add my own email/slack notification when this happens so I can inspect as soon as possible. But I don't think reliably passing the OAuth2 flow in the test is possible. Maybe if they only wanted username & password, but at the moment they split the login form to several steps, add some 2FA or captcha, it gets tough to the point where it wasn't worth for me to pursue further.

Hope it helped, maybe someone else has a better idea.

1 like
jan_zikmund's avatar

btw if this isn't good enough for you, you might try with some virtual browser and write the test in a form of actually sending the browser to authentication URL, tell it to fill fields, click submit, wait if 2FA question shows up etc. Depends how the authentication is protected, but you might get lucky with this, certainly more convenient than sending requests from PHP and work with the responses, as there even a bit of javascript just gives you a ton of headaches.

If that's something you want to try, look at Laravel Dusk. But as I say, be ready to spend quite some time on it with potentially no result whatsoever.

1 like
SereySoksan's avatar

@jan_zikmund Thank you for your useful information. This help me a lot, I'll spend some time to explore more with Laravel Dusk.

Please or to participate in this conversation.