@ContextHierarchy Example in Spring Test

By Arvind Rai, November 21, 2019
This page will walk through @ContextHierarchy annotation example in Spring test. The @ContextHierarchy is used at class level in integration test classes to define a hierarchy of ApplicationContext instances. The @ContextHierarchy defines a list of one or more @ContextConfiguration instances which defines a level in the context hierarchy. The @ContextHierarchy can be used for single test class as well as in test class hierarchy. Context can be merged and overridden using named context in context hierarchy.
Find the sample code to use @ContextHierarchy in integration test class using JavaConfig.
@ExtendWith(SpringExtension.class)
@ContextHierarchy({
	@ContextConfiguration(classes = AppConfig1.class),
	@ContextConfiguration(classes = AppConfig2.class),
	@ContextConfiguration(classes = AppConfig3.class)	
})
public class MyAppTest {
  ------
} 
Find the sample code with XML configuration.
@ExtendWith(SpringExtension.class)
@ContextHierarchy({
	@ContextConfiguration("app-config1.xml"),
	@ContextConfiguration("app-config2.xml"),
	@ContextConfiguration("app-config3.xml")
})
public class MyAppTest {
  ------
} 

Now let us discuss using @ContextHierarchy in our integration test classes in detail.

Technologies Used

Find the technologies being used in our example.
1. Java 11
2. Spring 5.2.0.RELEASE
3. Spring Boot 2.2.0.RELEASE
4. JUnit 5.3.2
5. Maven 3.5.2
6. Eclipse 2018-09

Java Configurations

Find the Java configurations being used in our test application.
AppConfig1.java
package com.concretepage;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig1 {
	@Bean("myBeanA")
	public String myBeanA() {
		return "My Bean A";
	}
} 
AppConfig2.java
package com.concretepage;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig2 {
	@Bean("myBeanB")
	public String myBeanB() {
		return "My Bean B";
	}
} 
AppConfig3.java
package com.concretepage;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig3 {
	@Bean("myBeanC")
	public String myBeanC() {
		return "My Bean C";
	}
} 
AppConfig4.java
package com.concretepage;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig4 {
	@Bean("myBeanD")
	public String myBeanC() {
		return "My Bean D";
	}
} 

@ContextHierarchy in Single Test Class

The @ContextHierarchy can be used in a single integration test class. In following test class, there are three context hierarchies. The context created by AppConfig1 is the parent context created by AppConfig2 and in the same way this context will be the parent of AppConfig3. Parent child relation of context will be as following.
context(AppConfig1) 
|
context(AppConfig2) 
|
context(AppConfig3) 
Find the example.
MyAppTest1.java
package com.concretepage;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.ContextHierarchy;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@ContextHierarchy({
	@ContextConfiguration(classes = AppConfig1.class),
	@ContextConfiguration(classes = AppConfig2.class),
	@ContextConfiguration(classes = AppConfig3.class)	
})
public class MyAppTest1 {
	@Autowired
	private ApplicationContext context;
	
	@Test
	public void testMethod1() { //Test result is SUCCESS
		assertEquals(true, context.containsBean("myBeanA"));
		assertEquals(true, context.containsBean("myBeanB"));
		assertEquals(true, context.containsBean("myBeanC"));
		printAllBeans();
	}

	void printAllBeans() {
		ApplicationContext ctx = context;
		while(ctx != null) {
		  System.out.println("---------");	
		  List.of(ctx.getBeanNamesForType(String.class))
		      .forEach(s -> System.out.println(s));
		  ctx = ctx.getParent();
		}
	}
} 
Output
---------
myBeanC
---------
myBeanB
---------
myBeanA 
Find the print screen of the output.
@ContextHierarchy Example in Spring Test

@ContextHierarchy in Class Hierarchy with Implicit Parent Context

In a class hierarchy, the @ContextHierarchy configures the context of parent test class as parent context for the context of child test class. Here we are creating an example in which we have parent class as MyAppBaseTest and it is extended by child test class MyAppTest2. The context in MyAppBaseTest is configured by AppConfig1 and the context in MyAppTest2 is configured by {AppConfig2, AppConfig3}. Find the parent child relation of context in our example.
context(AppConfig1) 
|
context({AppConfig2, AppConfig3}) 
Find the example.
MyAppBaseTest.java
package com.concretepage;
import java.util.List;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = AppConfig1.class)
public class MyAppBaseTest {
	@Autowired
	protected ApplicationContext context;
	void printAllBeans() {
		ApplicationContext ctx = context;
		while(ctx != null) {
		  System.out.println("---------");	
		  List.of(ctx.getBeanNamesForType(String.class))
		      .forEach(s -> System.out.println(s));
		  ctx = ctx.getParent();
		}
	}
} 
MyAppTest2.java
package com.concretepage;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.ContextHierarchy;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@ContextHierarchy({
	@ContextConfiguration(classes = {AppConfig2.class, AppConfig3.class})	
})
public class MyAppTest2 extends MyAppBaseTest {
	@Test
	public void testMethod1() { //Test result is SUCCESS
		assertEquals(true, context.containsBean("myBeanA"));
		assertEquals(true, context.containsBean("myBeanB"));
		assertEquals(true, context.containsBean("myBeanC"));
		printAllBeans();
	}
} 
Output
---------
myBeanB
myBeanC
---------
myBeanA 

@ContextHierarchy in Class Hierarchy with Merged Context

In a context hierarchy, we can merge context configurations for specific levels using named hierarchy levels. In our example we have a base test class as AppBaseTest which has named context configurations with name parent for AppConfig1 and child for AppConfig2. Now we will create a test class MyAppTest3 extending AppBaseTest. In MyAppTest3 we are using same named context configuration i.e. child for AppConfig3. So in MyAppTest3, the context of AppConfig2 and AppConfig3 will be merged. Find the parent child relation of context in our example.
context(AppConfig1) 
|
context({AppConfig2, AppConfig3})
|
context(AppConfig4) 
Find the example.
AppBaseTest.java
package com.concretepage;
import java.util.List;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.ContextHierarchy;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@ContextHierarchy({
	@ContextConfiguration(name = "parent", classes = AppConfig1.class),
	@ContextConfiguration(name = "child", classes = AppConfig2.class)
	
})
public class AppBaseTest {
	@Autowired
	protected ApplicationContext context;
	void printAllBeans() {
		ApplicationContext ctx = context;
		while(ctx != null) {
		  System.out.println("---------");	
		  List.of(ctx.getBeanNamesForType(String.class))
		      .forEach(s -> System.out.println(s));
		  ctx = ctx.getParent();
		}
	}
} 
MyAppTest3.java
package com.concretepage;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.ContextHierarchy;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@ContextHierarchy({
	@ContextConfiguration(name = "child", classes = AppConfig3.class),
	@ContextConfiguration(classes = AppConfig4.class)	
})
public class MyAppTest3 extends AppBaseTest {
	@Test
	public void testMethod1() { //Test result is SUCCESS
		assertEquals(true, context.containsBean("myBeanA"));
		assertEquals(true, context.containsBean("myBeanB"));
		assertEquals(true, context.containsBean("myBeanC"));
		assertEquals(true, context.containsBean("myBeanD"));
		printAllBeans();
	}
} 
Output
---------
myBeanD
---------
myBeanB
myBeanC
---------
myBeanA 

@ContextHierarchy in Class Hierarchy with Overridden Context

The named context in the context hierarchy configured by @ContextHierarchy can be overridden by setting inheritLocations element of @ContextConfiguration as false. In our example we have following parent child relation of context.
context(AppConfig1) 
|
context(AppConfig3)
|
context(AppConfig4) 
Find the example.
MyAppTest4.java
package com.concretepage;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.ContextHierarchy;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@ContextHierarchy({
	@ContextConfiguration(name = "child", inheritLocations = false, classes = AppConfig3.class),
	@ContextConfiguration(classes = AppConfig4.class)	
})
public class MyAppTest4 extends AppBaseTest {
	@Test
	public void testMethod1() { //Test result is SUCCESS
		assertEquals(true, context.containsBean("myBeanA"));
		assertEquals(false, context.containsBean("myBeanB"));
		assertEquals(true, context.containsBean("myBeanC"));
		assertEquals(true, context.containsBean("myBeanD"));
		printAllBeans();
	}
} 
Output
---------
myBeanD
---------
myBeanC
---------
myBeanA 

References

Spring testing: @ContextHierarchy
Spring doc: @ContextHierarchy

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us