skip to content

What does @ContextConfiguration do, and how do its `classes` and `locations` attributes differ?

level: juniorimportance: must knowfreq 70%

answer

  1. classes = Java config, locations = XML/Groovy
  2. one style per declaration, not both
  3. empty -> nested @Configuration or <Test>-context.xml
  4. merged into MergedContextConfiguration = cache key
  5. TCF recipe, driven by SpringExtension

basics

~10 s

@ContextConfiguration tells the Spring TestContext Framework how to build the ApplicationContext for a test. classes points to @Configuration/component classes; locations (or value) points to XML or Groovy resource files.

solid answer

~40 s

@ContextConfiguration is a class-level annotation that declares how to load and configure the ApplicationContext used by an integration test. Its `classes` attribute lists Java @Configuration or component classes (annotation-based config), while `locations`/`value` lists XML or Groovy resource paths (`classpath:`/relative). You pick one style per level; mixing both in a single declaration isn't supported by the default loaders. If you specify neither, the framework auto-detects: it looks for static nested @Configuration classes, or an XML file named `<TestClass>-context.xml` beside the test. The resolved config is combined with active profiles, initializers, and the loader into a MergedContextConfiguration, which also becomes the context cache key so the same context is reused across tests.

code

java · 22 lines
java
// Java-based (component) configuration
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = { AppConfig.class, TestBeans.class })
class OrderServiceTest {
    @Autowired OrderService service;
}

// XML / Groovy resource configuration
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = { "classpath:app-context.xml" })
class LegacyOrderServiceTest {
    @Autowired OrderService service;
}

// Convention: static nested @Configuration is auto-detected
@ExtendWith(SpringExtension.class)
@ContextConfiguration
class ConventionTest {
    @Configuration
    static class Config { @Bean OrderService svc() { return new OrderService(); } }
    @Autowired OrderService service;
}

go deeper

for a junior

Know classes = Java config, locations/value = XML/Groovy, and that it configures the test's ApplicationContext.

for a middle

Add default detection (nested @Configuration, <Test>-context.xml) and the merged-config context cache key.

for a senior

Discuss inheritance/merging of config from superclasses and the loader delegation that picks classes vs locations.

for a principal

Frame it around MergedContextConfiguration equality driving cache reuse and suite-level performance strategy.

## What it is `@ContextConfiguration` is a class-level annotation from `org.springframework.test.context`. It is the core of the **Spring TestContext Framework (TCF)** — it tells the framework *how* to build the `ApplicationContext` that your integration test runs against. It does not itself run anything; `@ExtendWith(SpringExtension.class)` (JUnit 5) or `SpringRunner` (JUnit 4) is what drives the TCF, and `@ContextConfiguration` supplies the recipe. (`@SpringBootTest` is a composed annotation that includes `@ContextConfiguration` under the hood, but auto-detection of Boot config classes is a separate concern.) ## Key attributes - **`classes`** — an array of `Class<?>` referencing Java-based configuration: `@Configuration` classes, `@Component` classes, or any class Spring can process as a bean source. This is *annotation-based* / *component-class* configuration, loaded by `AnnotationConfigContextLoader`. - **`locations`** (and its alias **`value`**) — an array of `String` resource paths to **XML** (`applicationContext.xml`) or **Groovy** (`context.groovy`) bean-definition files. Paths can be `classpath:`-prefixed, absolute (`/com/acme/beans.xml`), or relative to the test class's package. Loaded by `GenericXmlContextLoader` / `GenericGroovyXmlContextLoader`. - **`initializers`** — `ApplicationContextInitializer` classes run before context refresh. - **`loader`** — an explicit `ContextLoader`/`SmartContextLoader`. - **`inheritLocations` / `inheritInitializers`** — control whether config from superclass tests is merged (default `true`). - **`name`** — used only with `@ContextHierarchy` to identify a level. ## classes vs locations They are two mutually-distinct ways to describe the *same* thing — bean definitions: - `classes` = programmatic/annotation config (modern default). - `locations` = external XML/Groovy resource config (legacy but fully supported). A single `@ContextConfiguration` should use **one** of them. The default `DelegatingSmartContextLoader` inspects which attribute is populated and delegates to the matching concrete loader; it does **not** load both `classes` and `locations` together for one declaration. ## Default detection (specify neither) If you write `@ContextConfiguration` with no `classes` and no `locations`, the loaders attempt **convention-based detection**: - `AnnotationConfigContextLoader` scans the test class for **static nested `@Configuration` classes** and uses them. - `GenericXmlContextLoader` looks for an XML file named **`<FullyQualifiedTestClassName-with-slashes>-context.xml`** on the classpath (e.g. `com/acme/MyTest-context.xml`). ## MergedContextConfiguration & caching Whatever you declare is normalized into a **`MergedContextConfiguration`** object (locations + classes + initializers + active profiles + property sources + loader + parent). This object's equality is the **context cache key**: two tests with the same merged config **share one cached ApplicationContext**, which is the single biggest performance lever in a Spring test suite. `@DirtiesContext` evicts a context from the cache. ## Gotchas - Relative XML paths are relative to the **test class package**, not the working directory. - Empty `@ContextConfiguration` with no nested config and no matching XML fails to load a context. - Config on a superclass test is **inherited and merged** by default — surprising if you didn't expect it (`inheritLocations=false` to override). - `classes` referencing a plain POJO with no stereotype still registers it as a bean (component-class semantics), which can surprise people expecting only `@Configuration`.

  • If you provide neither classes nor locations, how does Spring decide what to load?
    It falls back to convention: AnnotationConfigContextLoader looks for static nested @Configuration classes on the test, and GenericXmlContextLoader looks for a classpath XML named `<TestClass>-context.xml`. If nothing is found, context loading fails.
  • Why does using the same @ContextConfiguration across many tests speed up the suite?
    The merged config becomes a cache key; identical configs share one ApplicationContext instance, so it's built once and reused instead of rebuilt per test class.

saying these in an interview costs you the question

  • Thinking @ContextConfiguration executes/runs the test rather than describing the context recipe
  • Claiming you can freely mix `classes` and `locations` in one declaration and both load together
  • Believing relative XML paths are resolved from the working directory rather than the test's package

context