Why phpunit is not getting the correct APP_ENV as specified in phpunit.xml?

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Decoding Environment Variables: Why PHPUnit Ignores Your phpunit.xml Settings

As developers working with complex environments, especially those involving Docker and frameworks like Laravel, managing environment variables can often lead to subtle but frustrating inconsistencies. A common point of confusion arises when trying to set specific variables within your phpunit.xml file only to find that the test runner ignores them in favor of existing system settings.

This post dives deep into why you might be observing this behavior with APP_ENV and how we can ensure our testing environments are predictable and reliable.

The Mystery of Environment Variable Precedence

You've encountered a classic problem related to environment variable precedence. When running tests inside a containerized setup (like Docker), the final value of an environment variable is determined by a hierarchy of sources:

  1. Shell/Docker Environment: Variables set at the shell level or within your docker-compose.yml file take the highest precedence.
  2. PHPUnit Runner: The variables explicitly defined within the <php> section of your phpunit.xml.
  3. Application Configuration: Framework-specific loading mechanisms (like Laravel's handling of .env files).

In your scenario, you correctly observed that variables not defined in docker-compose.yml are picked up by PHPUnit. However, when dealing with framework-specific variables like APP_ENV, the system defaults to the established environment provided by the container setup.

Why APP_ENV Behaves Differently

The reason APP_ENV seems to be ignored or overridden is often related to how Laravel initializes its application context. In many setups, especially when using Docker, the initial state of the application environment is baked into the container's base image or the service definition (docker-compose.yml).

When you set APP_ENV=local in your docker-compose, that value is established early in the container lifecycle. When PHPUnit executes, it inherits this pre-existing context. While PHPUnit can inject new variables, framework components often prioritize the environment already loaded by the application bootstrap process over runtime test configuration for core settings like the application environment.

Analyzing Your Configuration Example

Let's look at your provided configuration to understand the flow:

phpunit.xml Snippet:

<php>
    <env name="APP_ENV" value="testing"/>
    <env name="CACHE_DRIVER" value="array"/>
    <!-- ... other variables -->
</php>

docker-compose.yml Snippet:

environment:
  - APP_ENV=local
  # ... other DB settings

The conflict arises because the system sees APP_ENV=local defined externally, and while PHPUnit attempts to set it to testing, the framework logic often defaults back to the loaded environment for core configuration unless explicitly told otherwise through specific service bindings. This is a common pitfall when trying to enforce strict testing isolation versus application runtime behavior.

Best Practices for Environment Management in Testing

Instead of fighting the existing environment, the most robust approach is to ensure your test setup completely isolates the execution context.

1. Use Dedicated Test Environments

For testing purposes, it is often better to define a separate set of environment variables explicitly within your test configuration rather than relying solely on overriding container settings. If you are testing Laravel components, consider ensuring your tests truly run in an isolated state.

2. Leverage Laravel's Testing Utilities

When working with Laravel, leverage the built-in testing utilities rather than manually redefining every single environment variable in phpunit.xml. For database interactions and specific setup, use Laravel's testing helpers. This ensures that framework services (which are designed to handle environment loading) are correctly engaged.

3. Keep PHPUnit for Execution Flow

Use the <php> block primarily for setting variables strictly required by the test runner itself (e.g., custom connection strings or specific flags), and rely on your container definitions for the overall application context.

If you need to run tests against a specific environment, ensure that your test setup explicitly targets that configuration. Always aim for clarity over implicit overrides. For more detailed insights into managing Laravel environments within your stack, exploring official resources like those provided by laravelcompany.com is highly recommended.

Conclusion

The issue you faced stems from the complex interaction between container orchestration settings and framework-specific environment loading. While PHPUnit provides powerful runtime configuration, it doesn't always override foundational application context set at the system level. By understanding this precedence and adopting a strategy that separates infrastructure definitions (Docker) from execution definitions (PHPUnit), you can write more predictable and maintainable test suites.