2020import io .microsphere .annotation .Nonnull ;
2121import io .microsphere .spring .core .annotation .GenericAnnotationAttributes ;
2222import org .junit .jupiter .api .Test ;
23+ import org .springframework .boot .test .context .FilteredClassLoader ;
2324import org .springframework .boot .test .context .SpringBootTest ;
25+ import org .springframework .boot .test .context .assertj .ApplicationContextAssertProvider ;
26+ import org .springframework .boot .test .context .runner .AbstractApplicationContextRunner ;
27+ import org .springframework .boot .test .context .runner .ApplicationContextRunner ;
28+ import org .springframework .context .ConfigurableApplicationContext ;
29+ import org .springframework .core .ResolvableType ;
2430
2531import java .util .Set ;
2632
2733import static io .microsphere .collection .SetUtils .newLinkedHashSet ;
34+ import static io .microsphere .text .FormatUtils .format ;
2835import static io .microsphere .util .ArrayUtils .EMPTY_CLASS_ARRAY ;
36+ import static io .microsphere .util .ClassUtils .newInstance ;
37+ import static org .assertj .core .api .Assertions .assertThat ;
38+ import static org .junit .jupiter .api .Assertions .assertInstanceOf ;
2939import static org .junit .jupiter .api .Assertions .assertNotNull ;
40+ import static org .springframework .boot .autoconfigure .AutoConfigurations .of ;
3041import static org .springframework .boot .test .context .SpringBootTest .WebEnvironment .NONE ;
3142import static org .springframework .core .ResolvableType .forClass ;
3243
3344/**
34- * Abstract class for auto-configuration class tests
45+ * Abstract class for auto-configuration class tests based on {@link AbstractApplicationContextRunner}
3546 *
3647 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
48+ * @see AbstractApplicationContextRunner
3749 * @see AutoConfigurationTest
50+ * @see WebAutoConfigurationTest
3851 * @since 1.0.0
3952 */
40- public abstract class AbstractAutoConfigurationTest <A > {
53+ public abstract class AbstractAutoConfigurationTest <A , R extends AbstractApplicationContextRunner > {
4154
4255 /**
4356 * The {@link Class class} of {@link SpringBootTest}
@@ -55,30 +68,72 @@ public abstract class AbstractAutoConfigurationTest<A> {
5568 */
5669 protected final boolean isWebApplication ;
5770
71+ protected final ResolvableType abstractAutoConfigurationTestType ;
72+
5873 /**
5974 * The {@link Class class} of auto-configuration
6075 */
6176 @ Nonnull
6277 protected Class <A > autoConfigurationClass ;
6378
79+ /**
80+ * The {@link Class class} of {@link AbstractApplicationContextRunner}
81+ */
82+ @ Nonnull
83+ protected Class <R > runnerClass ;
84+
85+ @ Nonnull
86+ protected final R runner ;
87+
6488 protected AbstractAutoConfigurationTest () {
6589 Class <?> type = getClass ();
6690 SpringBootTest springBootTest = type .getAnnotation (SPRING_BOOT_TEST_CLASS );
6791 assertNotNull (springBootTest , "The @SpringBootTest must not be annotated on " + type );
6892 this .springBootTestAttributes = GenericAnnotationAttributes .of (springBootTest );
6993 this .isWebApplication = !NONE .equals (springBootTestAttributes .get ("webEnvironment" ));
70- this .autoConfigurationClass = (Class <A >) forClass (getClass ())
71- .as (AbstractAutoConfigurationTest .class ).resolveGeneric (0 );
94+ this .abstractAutoConfigurationTestType = forClass (getClass ()).as (AbstractAutoConfigurationTest .class );
95+ this .autoConfigurationClass = (Class <A >) abstractAutoConfigurationTestType .resolveGeneric (0 );
96+ this .runnerClass = (Class <R >) abstractAutoConfigurationTestType .resolveGeneric (1 );
97+ this .runner = newRunner ();
98+ if (!isWebApplication ) {
99+ assertInstanceOf (ApplicationContextRunner .class , this .runner ,
100+ format ("The runner class[{}] must be ApplicationContextRunner when the auto-configuration test is not a web application" , this .runner .getClass ().getName ()));
101+ }
102+ }
103+
104+ protected R newRunner () {
105+ R runner = newInstance (runnerClass );
106+ return initRunner (runner );
107+ }
108+
109+ protected R initRunner (R runner ) {
110+ String [] propertyValues = getPropertyValues ();
111+ Class <?>[] classes = getClasses ();
112+ return (R ) runner .withPropertyValues (propertyValues )
113+ .withConfiguration (of (this .autoConfigurationClass ))
114+ .withConfiguration (of (classes ));
72115 }
73116
74117 @ Test
75- protected abstract void testAutoConfiguredClasses ();
118+ protected void testAutoConfiguredClasses () {
119+ for (Class <?> autoConfiguredClass : getAutoConfiguredClasses ()) {
120+ assertAutoConfiguredClass (autoConfiguredClass );
121+ }
122+ }
76123
77124 @ Test
78- protected abstract void testOnGlobalDisabledProperty ();
125+ protected void testOnGlobalDisabledProperty () {
126+ for (String propertyValue : getGlobalDisabledPropertyValues ()) {
127+ assertDisabledProperty (propertyValue , getAutoConfiguredClasses ());
128+ }
129+ }
79130
80131 @ Test
81- protected abstract void testOnGlobalMissingClass ();
132+ protected void testOnGlobalMissingClass () {
133+ for (Class <?> missingClass : getGlobalMissingClasses ()) {
134+ assertFilteredClass (missingClass .getName (), getAutoConfiguredClasses ());
135+ }
136+ }
82137
83138 @ Nonnull
84139 protected final String [] getPropertyValues () {
@@ -131,4 +186,41 @@ protected final Class<?>[] getClasses() {
131186 * @param globalMissingClasses the global missing classes
132187 */
133188 protected abstract void configureGlobalMissingClasses (Set <Class <?>> globalMissingClasses );
189+
190+ protected void assertAutoConfiguredClass (Class <?> autoConfiguredClass ) {
191+ assertAutoConfiguredClass (this .runner , autoConfiguredClass );
192+ }
193+
194+ protected void assertDisabledProperty (String propertyValue , Class <?>... beanClasses ) {
195+ assertDisabledProperty (this .runner , propertyValue , beanClasses );
196+ }
197+
198+ protected void assertFilteredClass (String filteredClass , Class <?>... beanClasses ) {
199+ assertFilteredClass (this .runner , filteredClass , beanClasses );
200+ }
201+
202+ public static <R extends AbstractApplicationContextRunner <R , C , A >, C extends ConfigurableApplicationContext , A extends ApplicationContextAssertProvider <C >>
203+ void assertAutoConfiguredClass (R runner , Class <?> autoConfiguredClass ) {
204+ runner .run (context -> {
205+ assertThat (context ).hasSingleBean (autoConfiguredClass );
206+ });
207+ }
208+
209+ public static <R extends AbstractApplicationContextRunner <R , C , A >, C extends ConfigurableApplicationContext , A extends ApplicationContextAssertProvider <C >>
210+ void assertDisabledProperty (R runner , String propertyValue , Class <?>... beanClasses ) {
211+ runner .withPropertyValues (propertyValue ).run (context -> {
212+ for (Class <?> beanClass : beanClasses ) {
213+ assertThat (context ).doesNotHaveBean (beanClass );
214+ }
215+ });
216+ }
217+
218+ public static <R extends AbstractApplicationContextRunner <R , C , A >, C extends ConfigurableApplicationContext , A extends ApplicationContextAssertProvider <C >>
219+ void assertFilteredClass (R runner , String filteredClass , Class <?>... beanClasses ) {
220+ runner .withClassLoader (new FilteredClassLoader (filteredClass )).run (context -> {
221+ for (Class <?> beanClass : beanClasses ) {
222+ assertThat (context ).doesNotHaveBean (beanClass );
223+ }
224+ });
225+ }
134226}
0 commit comments