spring 跨junit测试类重用spring应用程序上下文
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8501975/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Reuse spring application context across junit test classes
提问by Ramesh
We've a bunch of JUnit test cases (Integration tests) and they are logically grouped into different test classes.
我们有一堆 JUnit 测试用例(集成测试),它们在逻辑上被分组到不同的测试类中。
We are able to load Spring application context once per test class and re-use it for all test cases in a JUnit test class as mentioned in http://static.springsource.org/spring/docs/current/spring-framework-reference/html/testing.html
我们能够为每个测试类加载一次 Spring 应用程序上下文,并将其重新用于 JUnit 测试类中的所有测试用例,如http://static.springsource.org/spring/docs/current/spring-framework-reference 中所述/html/testing.html
However, we were just wondering if there is a way to load Spring application context only once for a bunch of JUnit test classes.
然而,我们只是想知道是否有一种方法可以为一堆 JUnit 测试类只加载一次 Spring 应用程序上下文。
FWIW, we use Spring 3.0.5, JUnit 4.5 and use Maven to build the project.
FWIW,我们使用 Spring 3.0.5、JUnit 4.5 并使用 Maven 构建项目。
回答by Tomasz Nurkiewicz
Yes, this is perfectly possible. All you have to do is to use the same locationsattribute in your test classes:
是的,这是完全可能的。你所要做的就是locations在你的测试类中使用相同的属性:
@ContextConfiguration(locations = "classpath:test-context.xml")
Spring caches application contexts by locationsattribute so if the same locationsappears for the second time, Spring uses the same context rather than creating a new one.
Spring 按locations属性缓存应用程序上下文,因此如果locations第二次出现相同的上下文,Spring 将使用相同的上下文而不是创建新的上下文。
I wrote an article about this feature: Speeding up Spring integration tests. Also it is described in details in Spring documentation: 9.3.2.1 Context management and caching.
我写了一篇关于这个特性的文章:加速 Spring 集成测试。在 Spring 文档中也有详细描述:9.3.2.1 Context management and caching。
This has an interesting implication. Because Spring does not know when JUnit is done, it caches all context foreverand closes them using JVM shutdown hook. This behavior (especially when you have a lot of test classes with different locations) might lead to excessive memory usage, memory leaks, etc. Another advantage of caching context.
这有一个有趣的含义。因为 Spring 不知道 JUnit 何时完成,它永远缓存所有上下文并使用 JVM 关闭钩子关闭它们。这种行为(特别是当你有很多不同的测试类时locations)可能会导致内存使用过多、内存泄漏等。缓存上下文的另一个优点。
回答by gerrytan
To add to Tomasz Nurkiewicz's answer, as of Spring 3.2.2 @ContextHierarchyannotation can be used to have separate, associated multiple context structure. This is helpful when multiple test classes want to share (for example) in-memory database setups (datasource, EntityManagerFactory, tx manager etc).
要添加Tomasz Nurkiewicz 的答案,从 Spring 3.2.2 开始,@ContextHierarchy注释可用于具有单独的、关联的多上下文结构。当多个测试类想要共享(例如)内存数据库设置(数据源、EntityManagerFactory、tx 管理器等)时,这很有用。
For example:
例如:
@ContextHierarchy({
@ContextConfiguration("/test-db-setup-context.xml"),
@ContextConfiguration("FirstTest-context.xml")
})
@RunWith(SpringJUnit4ClassRunner.class)
public class FirstTest {
...
}
@ContextHierarchy({
@ContextConfiguration("/test-db-setup-context.xml"),
@ContextConfiguration("SecondTest-context.xml")
})
@RunWith(SpringJUnit4ClassRunner.class)
public class SecondTest {
...
}
By having this setup the context that uses "test-db-setup-context.xml" will only be created once, but beans inside it can be injected to individual unit test's context
通过进行此设置,使用“test-db-setup-context.xml”的上下文将只创建一次,但其中的 bean 可以注入到单个单元测试的上下文中
More on the manual: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html#testcontext-ctx-management(search for "context hierarchy")
更多关于手册:http: //docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html#testcontext-ctx-management(搜索“上下文层次结构”)
回答by Saurabh Gour
Basically spring is smart enough to configure this for you if you have the same application context configuration across the different test classes. For instance let's say you have two classes A and B as follows:
如果您在不同的测试类中具有相同的应用程序上下文配置,那么基本上 spring 足够聪明,可以为您配置它。例如,假设您有两个类 A 和 B,如下所示:
@ActiveProfiles("h2")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class A {
@MockBean
private C c;
//Autowired fields, test cases etc...
}
@ActiveProfiles("h2")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class B {
@MockBean
private D d;
//Autowired fields, test cases etc...
}
In this example class A mocks bean C, whereas class B mocks bean D. So, spring considers these as two different configurations and thus would load the application context once for class A and once for class B.
在此示例中,类 A 模拟 bean C,而类 B 模拟 bean D。因此,spring 将它们视为两种不同的配置,因此将为类 A 加载应用程序上下文一次,为类 B 加载一次。
If instead, we'd want to have spring share the application context between these two classes, they would have to look something as follows:
相反,如果我们希望 spring 在这两个类之间共享应用程序上下文,则它们必须如下所示:
@ActiveProfiles("h2")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class A {
@MockBean
private C c;
@MockBean
private D d;
//Autowired fields, test cases etc...
}
@ActiveProfiles("h2")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class B {
@MockBean
private C c;
@MockBean
private D d;
//Autowired fields, test cases etc...
}
If you wire up your classes like this, spring would load the application context only once either for class A or B depending on which class among the two is ran first in the test suite. This could be replicated across multiple test classes, only criteria is that you should not customize the test classes differently. Any customization that results in the test class to be different from the other(in the eyes of spring) would end up creating another application context by spring.
如果你像这样连接你的类,spring 将只为类 A 或 B 加载应用程序上下文一次,具体取决于这两个类中的哪个类在测试套件中首先运行。这可以跨多个测试类复制,唯一的标准是您不应以不同的方式自定义测试类。任何导致测试类与其他类不同的定制(在 spring 眼中)最终都会由 spring 创建另一个应用程序上下文。
回答by dileep gudla
create your configuaration class like below
创建您的配置类,如下所示
@ActiveProfiles("local")
@RunWith(SpringJUnit4ClassRunner.class )
@SpringBootTest(classes ={add your spring beans configuration classess})
@TestPropertySource(properties = {"spring.config.location=classpath:application"})
@ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)
public class RunConfigration {
private ClassLoader classloader = Thread.currentThread().getContextClassLoader();
private static final Logger LOG = LoggerFactory.getLogger(S2BXISINServiceTest.class);
//auto wire all the beans you wanted to use in your test classes
@Autowired
public XYZ xyz;
@Autowired
public ABC abc;
}
Create your test suite like below
@RunWith(Suite.class)
@Suite.SuiteClasses({Test1.class,test2.class})
public class TestSuite extends RunConfigration {
private ClassLoader classloader = Thread.currentThread().getContextClassLoader();
private static final Logger LOG = LoggerFactory.getLogger(TestSuite.class);
}
Create your test classes like below
创建您的测试类,如下所示
public class Test1 extends RunConfigration {
@Test
public void test1()
{
you can use autowired beans of RunConfigration classes here
}
}
public class Test2a extends RunConfigration {
@Test
public void test2()
{
you can use autowired beans of RunConfigration classes here
}
}

