3

I'm working on the D8 version of the CAS module. To integrate with a single sign on CAS server, this module will have to redirect the user to the CAS server often, and occasionally make cURL requests to that server for validation of various tokens. I'm struggling to write functional tests because of this.

I have a Drupal controller that will redirect the user to a number of places and invoke actions on a number of services, some of which may make cURL requests to the CAS server.

When the controller redirects to the server, I can just tell my web test to NOT follow redirects by overriding the property maxiumRedirects and setting it 0, then inspecting the response to make sure it was a redirect.

But, Since this controller may invoke services that make cURL requests to the CAS server, how would I handle that in a functional test, where that external service does not exist? In a unit test, I can mock the response from Guzzle, but can I do that in a functional test? Is my only option to create a test "server" module (with all the routes defined that CAS client makes requests to) that is enabled only for testing and would be used for testing my CAS client module?

2
  • I'm not completely sure I understand what the question is. While your question is interesting (I like high level testing), I don't quite see what part that is Drupal specific, so I'm not sure it's on topic.
    – Letharion
    Oct 20, 2014 at 13:40
  • I re-wrote some of the text above to hopefully be more clear. This is Drupal related because I'm working within Drupal's Simpletest module. If Drupal used phpUnit for functional testing (which seems to be commonly done now) then I believe I could mock the Guzzle response for the API calls made.
    – Brian
    Oct 20, 2014 at 14:04

2 Answers 2

4

Depending on what exactly you want to do, what we've done multiple times is make the domain/URL to which you redirect to configurable, and then configure it to redirect back to your site.

Then implement dummy routes there in a test module, do whatever you want and redirect back.

This was already possible in 7.x and hasn't really changed. It is sometimes more complicated to set up, but has the advantage that you are testing much more of your actual code and integration.

if you use @larowlan's approach, you could also just write unit tests for your service but I like to have most code covered with functional tests (too). I've seen it in core already many times that unit tests and their mocks get out of sync with how things really work, and then they are testing something that no longer exists. The more you have to mock, the bigger that risk becomes.

Note that, no matter which approach you chose, moving as much logic as possible into a service or even multiple services makes sense anyway and allows you to use unit tests for things that they are good at. Testing all possible cases, error handling/conditions and so on.

3

Make the requests performed by another service (let's call it a connector service) and inject that into the controller. This service would have guzzle client injected. Create an interface for the service and type hint that. Create a test module inside your module and make it hidden. In the test module use the service alter pattern to swap out the real connector service with a test one. The test one can implement another interface called mock connector which has extra methods to set the expected return or can just be wired to return fixed data. In your simple test make sure the rest module is enabled. Then you can test. This is where decoupling shines.

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.