2

I'm writing unit tests for an API built in Laravel. I have a database instance specific for running tests against and have configured the phpunit.xml to tell Laravel to use that db during testing.

However, my issue is when it comes to tests that perform a HTTP request to a route:

$response = $this->json('POST', route('api.login'), [
    'email' => '[email protected]',
    'password' => 'really.secure.password',
]);

The above request goes via my local network and from the application's point of view this is just another request, it doesn't know this is PHPUnit calling, so the auth token is created in my main database (not the testing database).

Now this feels like a pretty common scenario that I am doing so I'm hoping I've just missed some small tip in all the documentation and tutorials.

One solution which feels a bit hacky is to add some middleware which detects if the user-agent header of the request is set to "PHPUnit" and somehow change the environment and database values via the middleware. That feels a bit dirty so I'm reluctant to do it without first asking the SO community.

Can you suggest an existing technique or more elegant approach?

6
  • It is irrelevant if your application knows if the request comes from PHPUnit or not, if your phpunit.xml is setup correctly it will overwrite the DB_CONNECTION and it can only write into the test database, so make sure the phpunit.xml is actually used. How are you running your tests? console? phpstorm? Commented Sep 16, 2020 at 9:41
  • 1
    @Remul I am SSHing into my Homestead box and running artisan test. I've used dd() to confirm that the env values from my phpunit.xml are being used and they are in PHPUnit but the controller code triggered by the request still uses the normal .env values. Commented Sep 16, 2020 at 9:47
  • Are you using createApplication() in your unit test? Commented Sep 16, 2020 at 10:05
  • @user8555937 no. But I have just looked it up in the PHPUnit code. Should I try calling that and then running the $this->app->json() instead of $this->json()? Commented Sep 16, 2020 at 10:14
  • @user8555937 OK, I just tried calling $this->createApplication(); in the setUp() method of my test and got exactly the same result. Token created in main database. Commented Sep 16, 2020 at 10:17

1 Answer 1

1

@MartinJoiner Have you found a solution to this problem ?

Though its an old question. Here is what I have done, which is not a perfect solution by any means. All db settings are coming from .env file. I have a separate .env.testing which is supposed to be used for testing only. Though phpunit knows the environment is testing , I have done the following in composer.json to ensure tests are using .env.testing

This means when an api call is made during tests, the local system is using .env.testing and ensures testing DB is used for both HTTP and phpunit .

    "scripts": {
        "test": [
            "cp .env.testing .env",
            "vendor/bin/phpunit",
            "cp .env.example .env"
        ],
    }

And then run tests via composer test .

However I have a bit of a different but related issue. I hope you may have a look and provide some guidance.

Sign up to request clarification or add additional context in comments.

1 Comment

I tried a very similar thing where I physically rewrote the .env file but this caused all sorts of horribly problems with cached configs and writing to the wrong db. My solution was actually 2-fold: I stopped using config:cache as a common command because it's very sticky so that's only a deployment step now. I also started using Request::create() in my code to make a request object and then passed it to app()->handle($request) to get my response, thus avoiding the network. Maybe I should write this up as a proper answer(?)

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.