Nov 4, 2015 | testing, laravel, dotenv

Environment specific variables in Laravel's testing environment

Warning: This post is over a year old. I don't always update old posts with new information, so some of this information may be out of date.

In Laravel, it's easy to set environment variables that are specific to your testing environment. Just edit your phpunit.xml file and set them as entries in the <php> block:

        <env name="APP_ENV" value="testing"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
        <env name="DB_DATABASE" value=":memory:"/>
        <env name="DB_CONNECTION" value="sqlite"/>
        <env name="TWILIO_FROM_NUMBER" value="+15005550006"/>

But what if you find yourself needing to exclude these values from version control?

My example

I'm getting back to work on PulledOver, which uses Twilio as its foundation. I wanted to write some tests for my TwilioClient class, which directly connects to Twilio's API, so I was using Twilio's Test Credentials to send fake calls to the API and examine their responses.

But that means I have a Twilio SID and Token that I'm not supposed to expose to the public, right? I even asked around on Twitter:

I got quite a few responses, and one from the CEO of Twilio (!):

OK, so I need to exclude them. But how? I scratched my head a few times, dropped a question in the company Slack, and went to sleep. I woke up this morning and the ever-resourceful Keith Damiani had an answer for me: use Dotenv (which Laravel uses to load .env) to load a .env.test file in Laravel's TestCase base class. DUH. Here's how you do it:

Implementing .env.test in Laravel

First, create a .env.test.example file and fill it with placeholders for whichever keys you want:


Next, copy .env.test.example to .env.test and fill in the actual values.

Add .env.test to your .gitignore file.

Finally, add these line to tests/TestCase.php's createApplication method, just below $app = require __DIR__.'/../bootstrap/app.php';:

Note: Dotenv has changed their syntax multiple times recently, so I'll show three different versions here:

// Old Dotenv
if (file_exists(dirname(__DIR__) . '/.env.test')) {
    Dotenv::load(dirname(__DIR__), '.env.test');

// Medium-old Dotenv
if (file_exists(dirname(__DIR__) . '/.env.test')) {
    (new \Dotenv\Dotenv(dirname(__DIR__), '.env.test'))->load();

// New Dotenv
if (file_exists(dirname(__DIR__) . '/.env.test')) {
    (\Dotenv\Dotenv::createImmutable(dirname(__DIR__), '.env.test'))->load();

That's it! Your .env.test environment variables are now pulled into any test you run that extends TestCase, but those values are safely kept out of version control.

Comments? I'm @stauffermatt on Twitter

Tags: testing  •  laravel  •  dotenv


For quick links to fresh content, and for more thoughts that don't make it to the blog.