Top 30 Dependency Injection Interview Questions and Answers
30 multiple-choice questions on Dependency Injection, drawn from 30 bites out of the 39 tagged Dependency Injection on Tezvyn. Answer them here or read straight down. Every question carries the correct option, why it is correct, and a link to the bite it came from.
30 questions. Pick an answer, or open “Show the answer” to read it.
Answers are graded in your browser. Nothing is saved, and no XP or streak is earned here. The app keeps score.
Question 1 of 30
Why does Angular treat dependency injection as a runtime architectural layer rather than relying on ES module imports like Vue?
Show the answer
Answer: c · It enables runtime resolution of service lifetimes and implementation swapping without changing consumer code or direct file coupling.
Angular's DI is a runtime inversion-of-control system that supports scoped lifetimes, tree-shakable providers, and test-time substitution without modifying consumer code. The boilerplate distractor is wrong because DI still requires constructor declarations; its architectural value lies in runtime indirection and hierarchical resolution, not syntax savings.
Read the full bite: Why is DI central to Angular architecture versus Vue's module system?
Question 2 of 30
In FastAPI, why should an async database session dependency wrap yield in try and place await session.close() in finally?
Show the answer
Answer: a · It guarantees cleanup runs even if the path operation raises an exception.
A try/finally block guarantees that await session.close() runs even when the path operation raises an exception, preventing database connection leaks. The thread pool issue in distractor C is caused by using def instead of async def, not by omitting exception handling.
Question 3 of 30
An abstract domain package and a concrete storage package import each other. Which refactor best restores clean architecture?
Show the answer
Answer: d · Define a storage interface in the domain layer and inject the concrete implementation at startup
Defining the interface in the domain layer and injecting the concrete implementation at startup inverts the dependency, which is the recommended pattern for layer violations. Merging is better reserved for packages with no clear hierarchy, and build tags are a red-flag workaround that avoids fixing the design.
Read the full bite: Why does Go forbid circular dependencies, and how do you resolve them?
Question 4 of 30
In FastAPI, which approach best implements a reusable current-user check that preserves OpenAPI docs integration and keeps endpoints testable?
Show the answer
Answer: a · Define a get_current_user dependency that uses OAuth2PasswordBearer, validates the token, returns a User model, and inject it into routes with Depends.
A dedicated get_current_user dependency keeps auth explicit in the signature, auto-documents security in OpenAPI, and enables test overrides via app.dependency_overrides. Middleware hides the dependency from the docs and complicates testing.
Read the full bite: How do you create a reusable current-user dependency in FastAPI?
Question 5 of 30
What is the main reason to declare a FastAPI dependency in a path operation parameter?
Show the answer
Answer: a · To let FastAPI automatically inject reusable logic so routes stay focused on HTTP concerns.
The correct answer is C because dependency injection allows FastAPI to wire reusable components into routes, keeping handlers clean. A is tempting because it describes calling helpers, but that misses the inversion-of-control pattern where the framework injects the dependency rather than the route calling it manually.
Read the full bite: How do you declare a function as a dependency, and why?
Question 6 of 30
Which is the correct way to apply a shared dependency to every route in an APIRouter without adding it to each endpoint signature?
Show the answer
Answer: d · Pass a list of Depends() instances to the dependencies parameter when creating the APIRouter
APIRouter's dependencies parameter automatically injects shared dependencies into every mounted route while keeping endpoint signatures clean and preserving OpenAPI docs. Middleware runs globally on all requests rather than being router-scoped, and custom decorators break FastAPI's automatic schema generation.
Read the full bite: How do you apply a dependency to an APIRouter without per-endpoint signatures?
Question 7 of 30
When you assign a mock to app.dependency_overrides[get_db] in FastAPI, what happens during the test and what must you do afterward?
Show the answer
Answer: b · FastAPI injects the mock exclusively, bypassing the original and its sub-dependencies, and you must manually clear overrides after the test.
FastAPI uses the replacement function exclusively and never executes the original dependency or its sub-dependencies. Option C is tempting but incorrect because sub-dependencies are fully bypassed, not preserved, and overrides persist until you manually clear them.
Read the full bite: How would you override a FastAPI dependency during testing?
Question 8 of 30
You need a FastAPI dependency that accepts roles in its constructor and validates the current user each request. Why use a callable class rather than a plain function?
Show the answer
Answer: b · The class __init__ receives configuration and sub-dependencies declaratively while __call__ handles per-request logic and OpenAPI integration
A callable class lets FastAPI resolve constructor sub-dependencies and configuration via __init__ while __call__ handles per-request execution and remains visible to OpenAPI. The tempting distractor wrongly claims you must manually instantiate the class inside the endpoint, which defeats automatic injection and is explicitly flagged as a red flag.
Read the full bite: How do you use a Python class as a FastAPI dependency?
Question 9 of 30
In FastAPI, a database-querying dependency is injected into both a path operation and a sub-dependency. By default, what happens during a single request?
Show the answer
Answer: c · The dependency runs once and the cached value is reused only within that request's dependency tree
FastAPI defaults to use_cache=True, so it executes the dependency once per request and reuses that cached value throughout the same request's dependency tree. Option A is a common misconception: FastAPI does not independently resolve every Depends() declaration; it avoids redundant work by caching within the request lifecycle.
Read the full bite: How does FastAPI cache dependencies within a single request?
Question 10 of 30
You need a FastAPI dependency that combines a path parameter and a request header. What is the correct implementation pattern?
Show the answer
Answer: d · Annotate each parameter in the dependency function with its source (e.g., Path, Header) and declare the function as a dependency with Depends().
FastAPI inspects dependency signatures using the same resolution engine as endpoints, so annotating parameters with Path, Header, or similar and using Depends() lets the framework inject them automatically. Option B is tempting for developers familiar with lower-level frameworks, but manually parsing Request bypasses validation and defeats the purpose of FastAPI's dependency injection system.
Read the full bite: How would you implement a dependency requiring multi-source parameters?
Question 11 of 30
You move a dependency that loads a 2GB ML model from a global FastAPI app dependency to a single path operation. What is the actual effect?
Show the answer
Answer: d · It runs only when that specific path is hit, yet still reloads the model on every request to that path.
Path-local dependencies are resolved per-request, so the expensive load repeats on every call to that route; moving it merely limits blast radius. Distractor D is wrong because limiting the dependency to one route does not eliminate per-request overhead, which is why expensive initialization belongs in a lifespan event or cached singleton.
Read the full bite: How does lifecycle differ for global vs path operation dependencies?
Question 12 of 30
In FastAPI, when a dependency callable declares its own parameters using Depends, how does the framework resolve them at runtime?
Show the answer
Answer: d · It builds a dependency graph, resolving sub-dependencies first and injecting their results into parent dependencies.
FastAPI's injection solver treats Depends declarations as nodes in a dependency graph, recursively resolving sub-dependencies and feeding their outputs into parent callables before the endpoint executes. This is fundamentally different from middleware, which intercepts requests at the ASGI layer rather than performing parameter-level resolution.
Read the full bite: Explain the internal role of the Depends class
Question 13 of 30
You need to enforce authentication on every /users endpoint while leaving /items public. What is the most maintainable FastAPI approach?
Show the answer
Answer: c · Pass dependencies=[Depends(get_current_user)] to the users APIRouter and omit it from the items router, then include both in the app.
Passing dependencies to APIRouter scopes authentication to that router only while keeping other routers unaffected and preserving OpenAPI docs. Adding Depends to every route manually violates DRY and makes refactoring painful, even though it produces the same runtime behavior.
Read the full bite: How to apply a dependency to only one FastAPI router?
Question 14 of 30
When scaling FastAPI beyond simple routes, what is the recommended pattern for combining framework-native Depends with a formal DI container?
Show the answer
Answer: a · Bootstrap a container during startup for singletons and deep graphs, then use thin Depends wrappers to resolve or build request-scoped services.
The card recommends a hybrid approach: a formal container initializes singletons and deep graphs during startup, while thin Depends callables bridge request-scoped resources into FastAPI. Option C is the red flag of using Depends for everything, which scatters construction logic and hurts testability, while C creates noisy transitive coupling in routes and D sacrifices explicit lifecycle management.
Read the full bite: How do you manage service lifecycle with FastAPI Depends versus formal DI?
Question 15 of 30
How do you override a dependency for a single APIRouter without affecting the main FastAPI application?
Show the answer
Answer: b · Instantiate a sub-application, set its dependency_overrides, include the router, and mount it in the main app
Only FastAPI application instances maintain a dependency_overrides dictionary; APIRouter is merely a route grouping mechanism with no such registry. Mounting a sub-application with its own overrides isolates the mock without leaking state into the main app or relying on fragile global mutations.
Read the full bite: Override a FastAPI dependency at the APIRouter level
Question 16 of 30
What is the most accurate description of how the Provider package relates to InheritedWidget?
Show the answer
Answer: d · Provider is a wrapper over InheritedWidget that adds lifecycle and ergonomics
Provider builds directly on InheritedWidget, adding boilerplate reduction, disposal, and scoped reads. It is not an independent store, so the reactive-store option is a common misconception.
Read the full bite: Provider package versus raw InheritedWidget
Question 17 of 30
What is the primary reason to use FastAPI's Security() utility instead of Depends() for authentication?
Show the answer
Answer: a · It signals to OpenAPI that a dependency is a security requirement, enabling interactive documentation.
The card emphasizes that the key distinction of Security() is its role in signaling security requirements to OpenAPI, which enables interactive documentation features like lock icons and 'Authorize' buttons. While Security() does work with functions that raise HTTPExceptions for authentication failures, standard Depends() can also be used with such functions, making the OpenAPI integration the primary differentiator.
Read the full bite: FastAPI's Security Utility: Dependencies for Auth
Question 18 of 30
For which task would a developer most appropriately access the raw Request object in a FastAPI endpoint?
Show the answer
Answer: d · Retrieving the client's IP address for logging purposes.
The card explicitly states that retrieving the client's IP address is a common and appropriate use case for accessing the raw Request object. Using the raw Request object for standard tasks like extracting query parameters or validating Pydantic models bypasses FastAPI's declarative syntax, validation, and documentation features, which is advised against.
Read the full bite: Accessing the Raw Request Object in FastAPI
Question 19 of 30
In a large multi-module Android codebase, which pattern correctly implements inversion of control for cross-feature navigation without violating the dependency rule?
Show the answer
Answer: b · Use a shared navigation contract module for route definitions, with each feature contributing handlers to a DI multibinding map resolved by the app module.
B correctly applies inversion of control by isolating features behind a contract module and delegating wiring to the app module via dependency injection. C is tempting but wrong because a monolithic common module still implicitly couples features and becomes an unmaintainable dumping ground.
Read the full bite: How do you navigate between feature modules without direct dependencies?
Question 20 of 30
Which pattern correctly wires SQLAlchemy from configuration to endpoint in FastAPI without risking connection leaks?
Show the answer
Answer: d · Define a module-level engine and sessionmaker, then yield request-scoped sessions in a dependency with cleanup in a finally block.
Option D is correct because a single engine manages the connection pool globally, and yielding sessions with a finally block ensures each request gets its own safely closed session. Option A is tempting but wrong because creating an engine per request is expensive and defeats connection pooling, quickly exhausting database resources.
Read the full bite: Describe SQLAlchemy setup in FastAPI from database config to endpoint
Question 21 of 30
Why should get_db use yield instead of return when providing a database session to FastAPI endpoints?
Show the answer
Answer: d · Yield ensures cleanup logic in the finally block runs after the endpoint completes.
Using yield with a finally block guarantees the session closes after the endpoint runs, even if an exception occurs. Reusing a cached session across requests, as in option C, breaks thread safety and causes concurrency issues.
Read the full bite: How do you use FastAPI dependency injection for database sessions?
Question 22 of 30
What does FastAPI automatically do when you inject an OAuth2PasswordBearer instance into an endpoint using Depends?
Show the answer
Answer: c · Expect a Bearer token in the Authorization header, return 401 if absent, and add security metadata to OpenAPI docs
Injecting OAuth2PasswordBearer via Depends tells FastAPI to require an Authorization: Bearer header, automatically return 401 if it is missing, and document the requirement in OpenAPI. Option D is tempting but wrong because the scheme itself does not query a database or return a user object; that requires a separate custom dependency.
Read the full bite: How do you protect a FastAPI endpoint using Depends and OAuth2PasswordBearer?
Question 23 of 30
When implementing JWT-based RBAC in FastAPI, how should you handle a request with a valid token but an insufficient role claim?
Show the answer
Answer: b · Use a parameterized dependency that depends on a base JWT decoder and raises 403 Forbidden
A parameterized dependency composed on a base JWT decoder keeps routes clean and correctly raises 403 because the token is valid but the user lacks permission. Returning 401 is wrong for valid tokens, and querying a database or hardcoding 'admin' violates the pattern of extracting roles from JWT claims.
Read the full bite: Implement RBAC in FastAPI with a JWT role dependency
Question 24 of 30
What is the main architectural benefit of using Hilt over manual dependency instantiation in Android?
Show the answer
Answer: c · It automates object graph construction and lifecycle-aware scoping at compile time
Hilt generates the object graph at compile time and manages lifecycle-aware scopes, so consumers receive dependencies without knowing how to construct them. Distractor B is wrong because Hilt uses compile-time annotation processing and code generation, not runtime reflection.
Read the full bite: What is Dependency Injection and Hilt's benefit over manual instantiation?
Question 25 of 30
You control the UserRepository source code and need to inject it into a HiltViewModel. Which approach follows Hilt best practices?
Show the answer
Answer: d · Annotate UserRepository's constructor with @Inject and declare it in the ViewModel's constructor; no module is needed for UserRepository.
Annotating UserRepository's constructor with @Inject lets Hilt automatically provide it to the ViewModel without a module because you control the source. Writing a @Provides module for a class you own is tempting but wrong because it adds unnecessary boilerplate and hides the graph from compile-time validation.
Read the full bite: How do you inject UserRepository into a ViewModel with Hilt?
Question 26 of 30
How does the lifecycle of an @ActivityRetainedScoped dependency differ from a @Singleton dependency in Hilt?
Show the answer
Answer: a · @Singleton lives for the app process, while @ActivityRetainedScoped survives config changes but dies when the activity finishes.
@Singleton is tied to the application process via SingletonComponent, whereas @ActivityRetainedScoped is retained across configuration changes by ActivityRetainedComponent but destroyed when the activity finishes. Option C is tempting because both scopes do outlive a single Activity instance, but they differ fundamentally in scope and lifecycle ownership.
Read the full bite: Explain Hilt scoping: @Singleton vs @ActivityRetainedScoped
Question 27 of 30
You need to inject both a logging and a plain OkHttpClient using Hilt. Which pattern best disambiguates the bindings without leaking creation details into consumers?
Show the answer
Answer: c · Define a custom @Qualifier, annotate two @Provides methods in a @Module, and annotate the injection sites
Custom qualifiers are the type-safe, idiomatic way to distinguish multiple bindings of the same type while keeping construction logic inside the module. Subclassing OkHttpClient and using @Binds is a common anti-pattern because @Binds cannot run builder configuration like addInterceptor, and wrapper types pollute the domain model.
Read the full bite: How do you inject two different OkHttpClient instances with Hilt?
Question 28 of 30
Why inject the NetworkService as a protocol rather than constructing it inside the ViewModel?
Show the answer
Answer: b · It lets tests substitute a mock so behaviour is deterministic and offline
Protocol injection lets the test pass a controllable mock, keeping the test fast, offline, and deterministic. Binary size and runtime speed are unrelated, and XCTest imposes no such requirement.
Read the full bite: Unit test a ViewModel with a mocked NetworkService
Question 29 of 30
Your teammate binds an interface to its @Inject-annotated implementation using @Provides in a concrete module. What is the main drawback compared to using @Binds?
Show the answer
Answer: c · It adds unnecessary overhead by generating a factory even though Dagger already knows how to construct the type
@Provides generates an intermediate factory even when the implementation already has an @Inject constructor, whereas @Binds links the interface to that implementation without extra generated code. Option A is wrong because @Provides is not merely a shorthand; it creates unnecessary overhead and serves a different purpose.
Read the full bite: Functional difference between @Binds and @Provides in Hilt
Question 30 of 30
You need to use a Hilt-provided SettingsManager inside a legacy ContentProvider. What is the proper Hilt escape hatch?
Show the answer
Answer: b · Create an @EntryPoint interface installed in SingletonComponent, expose SettingsManager, and retrieve it via EntryPointAccessors.fromApplication in onCreate
The Android framework instantiates ContentProvider, so Hilt cannot perform field injection; you must define an EntryPoint in SingletonComponent and retrieve it with EntryPointAccessors.fromApplication. Option A is wrong because Hilt does not support member injection for framework-instantiated classes like ContentProvider.
Read the full bite: How would you access a Hilt dependency in a non-injectable ContentProvider?
Could you explain these out loud?
That is what an interview actually tests. Tezvyn gives you questions like these with what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.