Commit 683484e4 authored by Phillip Webb's avatar Phillip Webb

Fix primary beans with ApplicationContextAssert

Update `ApplicationContextAssert.getBean` so that multiple beans are
supported as long as one of them is primary. This aligns better with
the way that the standard `ApplicationContext.getBean` method works.

Closes gh-14874
parent 06f1a0e6
......@@ -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<C extends ApplicationContext>
"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
......
......@@ -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();
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment