2

I'm following roughly the TDD style as explained in the "Obey the Testing Goat" book: You have a functional test for your (Django, in my case) web app that tests the observable behaviour via the Selenium webdriver. And then once you write a failing functional test for the behavior you want to see, you'll then do the TDD loop to implement that functionality.

Now, the functionality I want to implement involves authenticating via OAuth2 with a REST API. The details probably don't matter, but it's the Adobe Lightroom API in case anyone is curious.

Immediately, I run into a few problems: The OAuth Redirect URI from Adobe doesn't accept localhost, so already using local unit tests for that wouldn't work. But also, I probably don't want to hit a live server with my (frequently run) unit tests.

But even the functional test would be something that first should run locally, and automatic, so the whole messing about with tokens and secrets seems messy.

For the unit tests, I'd be fine mocking out everything. Probably the whole external REST access should be hidden in its own class, and then I just create a dummy version of that class with the same interface. But for the integration test I obviously don't want to mock out everything, but it seems like I have to unless I do all the functional testing on a live server with https endpoint so that Adobe is happy with the OAuth process.

Any good practices and patterns I could use?

EDIT: Someone vote close due to "needs more focus", so maybe the one question I would like to steer the discussion towards is design approaches / testing techniques to deal with "unwieldy" external parts. The fact that it's OAuth in my case is secondary.

2
  • "The OAuth Redirect URI from Adobe doesn't accept localhost" — have you tried modifying your hosts file to map a made-up domain name to 127.0.0.1? Commented Aug 27, 2022 at 13:51
  • If it is truly a redirect. Commented Aug 27, 2022 at 13:52

2 Answers 2

5

I think you have to live with the fact that some things are not suitable for test automation. For example, when running automated tests regularly and frequently simply isn't affordable, because it would produce way more costs than the tests can be expected to save.

Here, you should remember that developers managed to build high quality software long before terms like TDD and BDD were invented. It is perfectly possible to implement a small, isolated component (for example, one which encapsulates a call to a third party service, including the authentication hazards), test it manually, inspect it, and when the quality seems sufficient, avoid to touch it as long as you don't have to, to reduce the risk of breaking something. Of course, the component should be "mockable", so it does not hinder anyone to write automated tests for parts of the system which rely on that component.

And yes, that approach will prevent rigorous refactoring and might lead to DRY violations - that's why one should try to keep those parts which are not subject to test automation small. Softwareengineering is the craft of tradeoffs, not the craft of following some articles of faith (a.k.a "best practices").

1
  • So in my case, write an adapter for the particular REST API I'm dealing with, test manually that it does what I think it does (due to the unwieldy authorization step), and then everywhere else just test against a mock / stub. Sounds like a plan!
    – Lagerbaer
    Commented Aug 27, 2022 at 20:16
0

I like to think of TDD as more of a design tool than a testing tool. It helps you clarify your requirements and come up with the right interfaces before you start implementing them. When you're working with an external REST API, someone else has already designed the interface and you're simply integrating with it. So mocking it is fine, even for an "acceptance" test that you would write as part of the TDD cycle. It helps you move faster during local development and you're not really losing much by not hitting a real endpoint.

Once you're done with your internal design and implementation, it might be worth writing a separate "integration" test that hits a real endpoint to verify the assumptions you made when you mocked it out earlier (and also lets you know if either side breaks the contract in the future). This is not something you would run often or even locally, but perhaps in some kind of staging environment before you deploy to production.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.