diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java index 4cb9615b92..027d71f050 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java @@ -32,8 +32,10 @@ import org.assertj.core.error.BasicErrorMessageFactory; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.util.Assert; import static org.assertj.core.api.Assertions.assertThat; @@ -273,17 +275,49 @@ public class ApplicationContextAssert "to contain bean of type:%n <%s>", type)); } String[] names = scope.getBeanNamesForType(getApplicationContext(), type); - if (names.length > 1) { + String name = (names.length > 0) ? getPrimary(names, scope) : null; + if (names.length > 1 && name == null) { throwAssertionError(new BasicErrorMessageFactory( "%nExpecting:%n <%s>%nsingle bean of type:%n <%s>%nbut found:%n <%s>", getApplicationContext(), type, names)); } - T bean = (names.length != 0) ? getApplicationContext().getBean(names[0], type) - : null; + T bean = (name != null) ? getApplicationContext().getBean(name, type) : null; return Assertions.assertThat(bean).as("Bean of type <%s> from <%s>", type, getApplicationContext()); } + private String getPrimary(String[] names, Scope scope) { + if (names.length == 1) { + return names[0]; + } + String primary = null; + for (String name : names) { + if (isPrimary(name, scope)) { + if (primary != null) { + return null; + } + primary = name; + } + } + return primary; + } + + private boolean isPrimary(String name, Scope scope) { + ApplicationContext context = getApplicationContext(); + while (context != null) { + if (context instanceof ConfigurableApplicationContext) { + ConfigurableListableBeanFactory factory = ((ConfigurableApplicationContext) context) + .getBeanFactory(); + if (factory.containsBean(name) + && factory.getMergedBeanDefinition(name).isPrimary()) { + return true; + } + } + context = (scope != Scope.NO_ANCESTORS) ? context.getParent() : null; + } + return false; + } + /** * Obtain a single bean of the given name from the application context, the bean * becoming the object under test. If no bean of the specified name can be found an diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/ApplicationContextAssertTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/ApplicationContextAssertTests.java index b2bd3830ec..6e2cb6fd2a 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/ApplicationContextAssertTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/ApplicationContextAssertTests.java @@ -22,6 +22,10 @@ import org.junit.Test; import org.springframework.boot.test.context.assertj.ApplicationContextAssert.Scope; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.context.support.StaticApplicationContext; import static org.assertj.core.api.Assertions.assertThat; @@ -244,6 +248,14 @@ public class ApplicationContextAssertTests { .withMessageContaining("but found"); } + @Test + public void getBeanOfTypeWhenHasPrimaryBeanShouldReturnPrimary() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( + PrimaryFooConfig.class); + assertThat(getAssert(context)).getBean(Foo.class).isInstanceOf(Bar.class); + context.close(); + } + @Test public void getBeanOfTypeWhenFailedToStartShouldFail() { assertThatExceptionOfType(AssertionError.class) @@ -423,4 +435,24 @@ public class ApplicationContextAssertTests { } + private static class Bar extends Foo { + + } + + @Configuration + static class PrimaryFooConfig { + + @Bean + public Foo foo() { + return new Foo(); + } + + @Bean + @Primary + public Bar bar() { + return new Bar(); + } + + } + }