Replies: 1 comment
-
Hey - been a while, but I just came across this - I had a bug whereby my user successfully resolved on the first hit to my application, but got stuck in a weird state of schrodinger's auth from that point onwards (using a separate API for our auth, but setting session & cookie values to allow login persistence across multiple sites) I fixed the issue but wanted to add a test to cover it, which meant hitting my application with a certain cookie & session state on the first request, then a different cookie & session state on a second request (simulating someone hitting the app having logged into another of our sites, being auto logged in, then refreshing). Anyway, I came across |
Beta Was this translation helpful? Give feedback.
-
Normally, i.e. in production mode, the whole Laravel application is spun up anew for each HTTP request. This implies that all services which are resolved by the global application object are re-resolved for each request and their constructors get called. During unit tests the global application object remains the same for all tests and each service class is resolved at most once when it is needed for the first time. While caching of objects of service classes in the application container is typically preferred due to efficiency reasons, it makes unit test to behave differently than real requests, i.e.
may produce a different outcome during unit tests than it would do in reality. The question is:
How do I ensure that the application container and the resolved services are re-resolved between HTTP request during unit test as they would in reality?
Specific example
The
AuthManager
is a service which is once resolved by the application container. In turn, theAuthManager
is responsible for resolving Guards and caches a resolved Guard internally. When a Guard is resolved for the first time, it is constructed. The call flow is basically as follows:AuthManager::guard()
; serves guard from cashguards
if available, callsresolve
otherwiseAuthManager::resolve()
creates the requested Guard by name and calls its creation method, e.g.createSessionDriver
AuthManager::createSessionDriver()
creates the actual Guard (here:SessionGuard
) and also sets the current request on the GuardNormally, i.e. in a production environment the code above works as expected. As for each request the whole application is re-created, an instance of
AuthManager
is re-created for each request. Consequently, the array of resolved Guards is initially empty for each request and gets created for each request and therewith bound to that request.During tests the application container survives, the
AuthManager
survives and so do the resolved Guards. In this specific example, this means the Guard remains bound to the very first request and resolves the user according to the first request not the currently tested request.Beta Was this translation helpful? Give feedback.
All reactions