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
This commit is contained in:
parent
06f1a0e6a2
commit
683484e4a8
|
|
@ -32,8 +32,10 @@ import org.assertj.core.error.BasicErrorMessageFactory;
|
||||||
|
|
||||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
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));
|
"to contain bean of type:%n <%s>", type));
|
||||||
}
|
}
|
||||||
String[] names = scope.getBeanNamesForType(getApplicationContext(), 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(
|
throwAssertionError(new BasicErrorMessageFactory(
|
||||||
"%nExpecting:%n <%s>%nsingle bean of type:%n <%s>%nbut found:%n <%s>",
|
"%nExpecting:%n <%s>%nsingle bean of type:%n <%s>%nbut found:%n <%s>",
|
||||||
getApplicationContext(), type, names));
|
getApplicationContext(), type, names));
|
||||||
}
|
}
|
||||||
T bean = (names.length != 0) ? getApplicationContext().getBean(names[0], type)
|
T bean = (name != null) ? getApplicationContext().getBean(name, type) : null;
|
||||||
: null;
|
|
||||||
return Assertions.assertThat(bean).as("Bean of type <%s> from <%s>", type,
|
return Assertions.assertThat(bean).as("Bean of type <%s> from <%s>", type,
|
||||||
getApplicationContext());
|
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
|
* 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
|
* 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.boot.test.context.assertj.ApplicationContextAssert.Scope;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
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 org.springframework.context.support.StaticApplicationContext;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
@ -244,6 +248,14 @@ public class ApplicationContextAssertTests {
|
||||||
.withMessageContaining("but found");
|
.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
|
@Test
|
||||||
public void getBeanOfTypeWhenFailedToStartShouldFail() {
|
public void getBeanOfTypeWhenFailedToStartShouldFail() {
|
||||||
assertThatExceptionOfType(AssertionError.class)
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue