Skip to content

Commit da04362

Browse files
committed
Log context cache statistics in the TCF
Prior to this commit, finding out how many application contexts had been loaded within a test suite required the use of reflection and a bit of hacking. This commit addresses this issue by logging ContextCache statistics whenever an application context is loaded by the Spring TestContext Framework (TCF). The log output can be enabled by setting the "org.springframework.test.context.cache" logging category to DEBUG. Issue: SPR-12409
1 parent 8b5fda5 commit da04362

File tree

4 files changed

+31
-29
lines changed

4 files changed

+31
-29
lines changed

spring-test/src/main/java/org/springframework/test/context/ContextCache.java

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
2222
import java.util.Map;
2323
import java.util.Set;
2424
import java.util.concurrent.ConcurrentHashMap;
25+
import java.util.concurrent.atomic.AtomicInteger;
2526

2627
import org.springframework.context.ApplicationContext;
2728
import org.springframework.context.ConfigurableApplicationContext;
@@ -64,9 +65,9 @@ class ContextCache {
6465
private final Map<MergedContextConfiguration, Set<MergedContextConfiguration>> hierarchyMap = new ConcurrentHashMap<MergedContextConfiguration, Set<MergedContextConfiguration>>(
6566
64);
6667

67-
private int hitCount;
68+
private final AtomicInteger hitCount = new AtomicInteger();
6869

69-
private int missCount;
70+
private final AtomicInteger missCount = new AtomicInteger();
7071

7172

7273
/**
@@ -84,8 +85,8 @@ void clear() {
8485
* Clears hit and miss count statistics for the cache (i.e., resets counters to zero).
8586
*/
8687
void clearStatistics() {
87-
this.hitCount = 0;
88-
this.missCount = 0;
88+
this.hitCount.set(0);
89+
this.missCount.set(0);
8990
}
9091

9192
/**
@@ -116,45 +117,31 @@ ApplicationContext get(MergedContextConfiguration key) {
116117
synchronized (monitor) {
117118
ApplicationContext context = this.contextMap.get(key);
118119
if (context == null) {
119-
incrementMissCount();
120+
this.missCount.incrementAndGet();
120121
}
121122
else {
122-
incrementHitCount();
123+
this.hitCount.incrementAndGet();
123124
}
124125
return context;
125126
}
126127
}
127128

128129
/**
129-
* Increment the hit count by one. A <em>hit</em> is an access to the cache, which
130-
* returned a non-null context for a queried key.
131-
*/
132-
private void incrementHitCount() {
133-
this.hitCount++;
134-
}
135-
136-
/**
137-
* Increment the miss count by one. A <em>miss</em> is an access to the cache, which
138-
* returned a {@code null} context for a queried key.
139-
*/
140-
private void incrementMissCount() {
141-
this.missCount++;
142-
}
143-
144-
/**
145-
* Get the overall hit count for this cache. A <em>hit</em> is an access to the cache,
146-
* which returned a non-null context for a queried key.
130+
* Get the overall hit count for this cache.
131+
* <p>A <em>hit</em> is an access to the cache, which returned a non-null context for
132+
* a queried key.
147133
*/
148134
int getHitCount() {
149-
return this.hitCount;
135+
return this.hitCount.get();
150136
}
151137

152138
/**
153-
* Get the overall miss count for this cache. A <em>miss</em> is an access to the
154-
* cache, which returned a {@code null} context for a queried key.
139+
* Get the overall miss count for this cache.
140+
* <p>A <em>miss</em> is an access to the cache, which returned a {@code null} context
141+
* for a queried key.
155142
*/
156143
int getMissCount() {
157-
return this.missCount;
144+
return this.missCount.get();
158145
}
159146

160147
/**

spring-test/src/main/java/org/springframework/test/context/DefaultCacheAwareContextLoaderDelegate.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ class DefaultCacheAwareContextLoaderDelegate implements CacheAwareContextLoaderD
3838

3939
private static final Log logger = LogFactory.getLog(DefaultCacheAwareContextLoaderDelegate.class);
4040

41+
private static final Log statsLogger = LogFactory.getLog("org.springframework.test.context.cache");
42+
4143
private final ContextCache contextCache;
4244

4345

@@ -98,6 +100,11 @@ public ApplicationContext loadContext(MergedContextConfiguration mergedContextCo
98100
mergedContextConfiguration));
99101
}
100102
}
103+
104+
if (statsLogger.isDebugEnabled()) {
105+
statsLogger.debug(String.format("Spring test ApplicationContext cache statistics: %s", contextCache));
106+
}
107+
101108
return context;
102109
}
103110
}

spring-test/src/test/resources/log4j.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ log4j.logger.org.springframework.test.context.ContextLoaderUtils=WARN
1515
log4j.logger.org.springframework.test.context.transaction.TransactionalTestExecutionListener=WARN
1616
log4j.logger.org.springframework.test.context.web=WARN
1717
log4j.logger.org.springframework.test.context=WARN
18+
log4j.logger.org.springframework.test.context.cache=WARN
1819

1920
#log4j.logger.org.springframework.test.context.support=INFO
2021
#log4j.logger.org.springframework.test.context.support.DelegatingSmartContextLoader=INFO

src/asciidoc/index.adoc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20851,6 +20851,12 @@ framework will not be able to cache application contexts between test classes an
2085120851
build process will run significantly slower as a result.
2085220852
====
2085320853

20854+
Since having a large number of application contexts loaded within a given test suite can
20855+
cause the suite to take an unnecessarily long time to execute, it is often beneficial to
20856+
know exactly how many contexts have been loaded and cached. To view the statistics for
20857+
the underlying context cache, simply set the log level for the
20858+
`org.springframework.test.context.cache` logging category to `DEBUG`.
20859+
2085420860
In the unlikely case that a test corrupts the application context and requires reloading
2085520861
-- for example, by modifying a bean definition or the state of an application object --
2085620862
you can annotate your test class or test method with `@DirtiesContext` (see the
@@ -20860,6 +20866,7 @@ context before executing the next test. Note that support for the `@DirtiesConte
2086020866
annotation is provided by the `DirtiesContextTestExecutionListener` which is enabled by
2086120867
default.
2086220868

20869+
2086320870
[[testcontext-ctx-management-ctx-hierarchies]]
2086420871
====== Context hierarchies
2086520872

0 commit comments

Comments
 (0)