Software Development Testing

Too often best practices for testing are an after-thought, or a non-thought with respect to the development and deployment of code.

This generally results in shortcuts or bandaids being applied to the SDLC of an organization which can build up over time and become a major constraint on the future product evolution.

With respect to a PHP driven application, my preference is PHPUnit. So briefly a friendly reminder to distinguish your tests by categorization, without opening up a can-of-worms on how to classify a test; we can do that later.

The simplest and easiest ways to get started with this is to organize your tests within PHPUnit, so you can run specific groups of tests along your deployment cycle.

For example, it’s generally a good practice to run your true unit tests on every commit. If they’re written correctly and concisely this shouldn’t introduce a bottleneck on the developers.

Building on that, this is a simple recommended approach for which tests to run along your pipeline:

  1. Unit
    1. On every commit
    2. After/during each pull-request being merged
  2. Integration
    1. On every preprod build; usually I do this with a jenkins/ansible build in a containerized environment that can hit specific api endpoints.
  3. Functional
    1. On every environment deployment. When deployed to env we’ll run tests specific for that environment to verify behaviors for things like billing rules, email filters, etc.
  4. UI
    1. After deployment; when deployed and “launched” we can run automated UI tests to verify behaviors and UI/UX interactions.
    2. These are typically lower importance/severity, so they can generally happen post-build.

API environment contextual responses with Symfony3 Subscribers for Dev vs. Non-Dev

According to the ideal 12 Factor App you want to store your configuration in the specific environment. This includes debugging, logging, and everything else your application does. When building an API, these days you want your response data to be JSON, unless you’re an XML holdout which case you’re still using XML. Regardless, while in production you want clear and concise error message responses that do not reveal too much information. However, outside of production you probably want a quick way to see at least the source file throwing the exception so you know where to begin without crawling logs for every iterative issue while in development. For this you’ll need your API response data to include some contextual debugging and/or exception information you normally wouldn’t want in your response. This is a perfect scenario for environment configuration, and Symfony has a great way we can handle this with an ExceptionSubscriber for “Dev” and for “Non-Dev” environments (in this example).

Here’s a brief breakdown of what we’re building:

  1. Service declaration for subscribing to exceptions in dev and default environments
  2. ExceptionSubscriber class that processes exceptions being thrown, and cleans up the response JSON (…and XML because we aren’t jerks).
  3. DevExceptionSubscriber that extends ExceptionSubscriber and adds some debug “stuff” to the response.

Declare the Default Service

Build ExceptionSubscriber

 

Extend ExceptionSubscriber for DevExceptionSubscriber

Here, we don’t filter any of the message content, so we can get the literal exception text thrown for exception classes we didn’t specifically write. This is particularly useful if we want to mask exceptions for invalid passwords so users cannot guess which usernames exist or not, and other business rule exceptions for Unauthorized or Access Denied messages where we don’t want to reveal too much.

Finally..

In use, you’ll know see responses like this:

CORS API supporting Symfony3 + Angular2

Is your API giving you trouble with a missing Access-Control-Allow-Origin header error?

Perhaps you enjoy living on the bleeding edge, and you’ve decided to build an app with Symfony3 + Anglar2 and you’ve seen this before?

XMLHttpRequest cannot load http://myapp.dev. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4000' is therefore not allowed access.

After many days of stressing and confusion I’ve identified what I believe to be the “easiest” solution to this problem, specifically if you’re using nginx.

Install nginx-extras (Debian/Ubuntu)

Configure NGINX

Failed Solutions

  1. I attempted nelmio/cors-bundle with limited success and various odd issues. Particularly the response would come back successful, but the browser would still react as if there was a 404 on the response Header. This resulted in Angular2 acting as though the response wasn’t even worth processing, and so it didn’t.
  2. I attempted hard-coding the header directly to the $response object in my frontend controller, but this made me feel dirty and ultimately was ignored by nginx anyway. I also would be shocked if this worked in any real environment using a load-balancer of any kind.
  3. Building a simplified version of nelmio/cors-bundle via a CorsListener EventListener yielded similar results to above in both respects. This appeared to be completely ignored by nginx, and resulted in no tangible change. An example implementation can be found here: https://www.snip2code.com/Snippet/87161/Allow-CORS-in-symfony2