diff --git a/build.gradle b/build.gradle index c20e666500..97726440a5 100644 --- a/build.gradle +++ b/build.gradle @@ -60,6 +60,8 @@ configure(allprojects) { project -> ext.jrubyVersion = "1.7.25" // JRuby 9000 only supported through JSR-223 (StandardScriptFactory) ext.jtaVersion = "1.2" ext.junitVersion = "4.12" + ext.junitJupiterVersion = '5.0.0-SNAPSHOT' + ext.junitPlatformVersion = '1.0.0-SNAPSHOT' ext.log4jVersion = "1.2.17" ext.nettyVersion = "4.1.1.Final" ext.okhttpVersion = "2.7.5" @@ -131,6 +133,8 @@ configure(allprojects) { project -> repositories { maven { url "https://repo.spring.io/libs-release" } + // For JUnit Platform and Jupiter snapshots: + maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } } dependencies { @@ -993,6 +997,7 @@ project("spring-test") { optional(project(":spring-webmvc-portlet")) optional(project(":spring-websocket")) optional("junit:junit:${junitVersion}") + optional("org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}") optional("org.testng:testng:${testngVersion}") optional("javax.inject:javax.inject:1") optional("javax.servlet:javax.servlet-api:3.0.1") @@ -1020,6 +1025,8 @@ project("spring-test") { testCompile("org.hibernate:hibernate-core:${hibernate4Version}") testCompile("org.hibernate:hibernate-entitymanager:${hibernate4Version}") testCompile("org.hibernate:hibernate-validator:${hibval5Version}") + // Enable use of the JUnitPlatform Runner + testCompile("org.junit.platform:junit-platform-runner:${junitPlatformVersion}") testCompile("com.thoughtworks.xstream:xstream:${xstreamVersion}") testCompile("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}") testCompile("com.rometools:rome:${romeVersion}") @@ -1034,7 +1041,9 @@ project("spring-test") { testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}") testCompile("org.apache.httpcomponents:httpclient:${httpclientVersion}") testCompile("javax.cache:cache-api:1.0.0") + testRuntime("org.junit.jupiter:junit-jupiter-engine:${junitJupiterVersion}") testRuntime("log4j:log4j:${log4jVersion}") + testRuntime("org.ehcache:ehcache:${ehcache3Version}") testRuntime("org.terracotta:management-model:2.0.0") } @@ -1053,7 +1062,9 @@ project("spring-test") { description = 'Runs JUnit tests.' dependsOn testNG useJUnit() - exclude "**/testng/**/*.*" + scanForTestClasses = false + include(['**/*Tests.class', '**/*Test.class', '**/SpringJUnitJupiterTestSuite.class']) + exclude(['**/testng/**/*.*']) } task aggregateTestReports(type: TestReport) { diff --git a/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringExtension.java b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringExtension.java new file mode 100644 index 0000000000..94d1063f26 --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringExtension.java @@ -0,0 +1,180 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; + +import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ContainerExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; +import org.junit.jupiter.api.extension.ExtensionContext.Store; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolver; +import org.junit.jupiter.api.extension.TestExtensionContext; +import org.junit.jupiter.api.extension.TestInstancePostProcessor; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.test.context.TestContextManager; +import org.springframework.test.context.junit.jupiter.support.ParameterAutowireUtils; +import org.springframework.util.Assert; + +/** + * {@code SpringExtension} integrates the Spring TestContext Framework + * into JUnit 5's Jupiter programming model. + * + *

To use this class, simply annotate a JUnit Jupiter based test class with + * {@code @ExtendWith(SpringExtension.class)}. + * + * @author Sam Brannen + * @since 5.0 + * @see org.springframework.test.context.junit.jupiter.SpringJUnitConfig + * @see org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig + * @see org.springframework.test.context.TestContextManager + */ +public class SpringExtension implements BeforeAllCallback, AfterAllCallback, TestInstancePostProcessor, + BeforeEachCallback, AfterEachCallback, ParameterResolver { + + /** + * {@link Namespace} in which {@code TestContextManagers} are stored, keyed + * by test class. + */ + private static final Namespace namespace = Namespace.create(SpringExtension.class); + + /** + * Delegates to {@link TestContextManager#beforeTestClass}. + */ + @Override + public void beforeAll(ContainerExtensionContext context) throws Exception { + getTestContextManager(context).beforeTestClass(); + } + + /** + * Delegates to {@link TestContextManager#afterTestClass}. + */ + @Override + public void afterAll(ContainerExtensionContext context) throws Exception { + try { + getTestContextManager(context).afterTestClass(); + } + finally { + context.getStore(namespace).remove(context.getTestClass().get()); + } + } + + /** + * Delegates to {@link TestContextManager#prepareTestInstance}. + */ + @Override + public void postProcessTestInstance(Object testInstance, ExtensionContext context) throws Exception { + getTestContextManager(context).prepareTestInstance(testInstance); + } + + /** + * Delegates to {@link TestContextManager#beforeTestMethod}. + */ + @Override + public void beforeEach(TestExtensionContext context) throws Exception { + Object testInstance = context.getTestInstance(); + Method testMethod = context.getTestMethod().get(); + getTestContextManager(context).beforeTestMethod(testInstance, testMethod); + } + + /** + * Delegates to {@link TestContextManager#afterTestMethod}. + */ + @Override + public void afterEach(TestExtensionContext context) throws Exception { + Object testInstance = context.getTestInstance(); + Method testMethod = context.getTestMethod().get(); + Throwable testException = context.getTestException().orElse(null); + getTestContextManager(context).afterTestMethod(testInstance, testMethod, testException); + } + + /** + * Determine if the value for the {@link Parameter} in the supplied + * {@link ParameterContext} should be autowired from the test's + * {@link ApplicationContext}. + *

Returns {@code true} if the parameter is declared in a {@link Constructor} + * that is annotated with {@link Autowired @Autowired} and otherwise delegates + * to {@link ParameterAutowireUtils#isAutowirable}. + *

WARNING: if the parameter is declared in a {@code Constructor} + * that is annotated with {@code @Autowired}, Spring will assume the responsibility + * for resolving all parameters in the constructor. Consequently, no other + * registered {@link ParameterResolver} will be able to resolve parameters. + * + * @see #resolve + * @see ParameterAutowireUtils#isAutowirable + */ + @Override + public boolean supports(ParameterContext parameterContext, ExtensionContext extensionContext) { + Parameter parameter = parameterContext.getParameter(); + Executable executable = parameter.getDeclaringExecutable(); + return (executable instanceof Constructor && AnnotatedElementUtils.hasAnnotation(executable, Autowired.class)) + || ParameterAutowireUtils.isAutowirable(parameter); + } + + /** + * Resolve a value for the {@link Parameter} in the supplied + * {@link ParameterContext} by retrieving the corresponding dependency + * from the test's {@link ApplicationContext}. + *

Delegates to {@link ParameterAutowireUtils#resolveDependency}. + * @see #supports + * @see ParameterAutowireUtils#resolveDependency + */ + @Override + public Object resolve(ParameterContext parameterContext, ExtensionContext extensionContext) { + Parameter parameter = parameterContext.getParameter(); + Class testClass = extensionContext.getTestClass().get(); + ApplicationContext applicationContext = getApplicationContext(extensionContext); + return ParameterAutowireUtils.resolveDependency(parameter, testClass, applicationContext); + } + + /** + * Get the {@link ApplicationContext} associated with the supplied + * {@code ExtensionContext}. + * @param context the current {@code ExtensionContext}; never {@code null} + * @return the application context + * @throws IllegalStateException if an error occurs while retrieving the + * application context + * @see org.springframework.test.context.TestContext#getApplicationContext() + */ + private ApplicationContext getApplicationContext(ExtensionContext context) { + return getTestContextManager(context).getTestContext().getApplicationContext(); + } + + /** + * Get the {@link TestContextManager} associated with the supplied + * {@code ExtensionContext}. + * @return the {@code TestContextManager}; never {@code null} + */ + private TestContextManager getTestContextManager(ExtensionContext context) { + Assert.notNull(context, "ExtensionContext must not be null"); + Class testClass = context.getTestClass().get(); + Store store = context.getStore(namespace); + return store.getOrComputeIfAbsent(testClass, TestContextManager::new, TestContextManager.class); + } + +} diff --git a/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringJUnitConfig.java b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringJUnitConfig.java new file mode 100644 index 0000000000..74a0ee98b7 --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringJUnitConfig.java @@ -0,0 +1,96 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.junit.jupiter.api.extension.ExtendWith; + +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.annotation.AliasFor; +import org.springframework.test.context.ContextConfiguration; + +/** + * {@code @SpringJUnitConfig} is a composed annotation that combines + * {@link ExtendWith @ExtendWith(SpringExtension.class)} from JUnit Jupiter with + * {@link ContextConfiguration @ContextConfiguration} from the Spring TestContext + * Framework. + * + * @author Sam Brannen + * @since 5.0 + * @see ExtendWith + * @see SpringExtension + * @see ContextConfiguration + * @see org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig + */ +@ExtendWith(SpringExtension.class) +@ContextConfiguration +@Documented +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface SpringJUnitConfig { + + /** + * Alias for {@link ContextConfiguration#classes}. + */ + @AliasFor(annotation = ContextConfiguration.class, attribute = "classes") + Class[] value() default {}; + + /** + * Alias for {@link ContextConfiguration#classes}. + */ + @AliasFor(annotation = ContextConfiguration.class) + Class[] classes() default {}; + + /** + * Alias for {@link ContextConfiguration#locations}. + */ + @AliasFor(annotation = ContextConfiguration.class) + String[] locations() default {}; + + /** + * Alias for {@link ContextConfiguration#initializers}. + */ + @AliasFor(annotation = ContextConfiguration.class) + Class>[] initializers() default {}; + + /** + * Alias for {@link ContextConfiguration#inheritLocations}. + */ + @AliasFor(annotation = ContextConfiguration.class) + boolean inheritLocations() default true; + + /** + * Alias for {@link ContextConfiguration#inheritInitializers}. + */ + @AliasFor(annotation = ContextConfiguration.class) + boolean inheritInitializers() default true; + + /** + * Alias for {@link ContextConfiguration#name}. + */ + @AliasFor(annotation = ContextConfiguration.class) + String name() default ""; + +} diff --git a/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/package-info.java b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/package-info.java new file mode 100644 index 0000000000..ceba54b4f7 --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/package-info.java @@ -0,0 +1,5 @@ +/** + * Core support for integrating the Spring TestContext Framework + * with the JUnit Jupiter extension model in JUnit 5. + */ +package org.springframework.test.context.junit.jupiter; diff --git a/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/support/MethodParameterFactory.java b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/support/MethodParameterFactory.java new file mode 100644 index 0000000000..37779b44aa --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/support/MethodParameterFactory.java @@ -0,0 +1,98 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter.support; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; + +import org.springframework.core.MethodParameter; +import org.springframework.core.annotation.SynthesizingMethodParameter; +import org.springframework.util.Assert; + +/** + * Factory for creating {@link MethodParameter} instances from Java 8 + * {@link Parameter Parameters}. + * + * @author Sam Brannen + * @since 5.0 + * @see ParameterAutowireUtils + * @see MethodParameter + * @see SynthesizingMethodParameter + * @see #createMethodParameter(Parameter) + * @see #createSynthesizingMethodParameter(Parameter) + */ +public abstract class MethodParameterFactory { + + private MethodParameterFactory() { + /* no-op */ + } + + /** + * Create a standard {@link MethodParameter} from the supplied {@link Parameter}. + *

Supports parameters declared in methods and constructors. + * @param parameter the parameter to create a {@code MethodParameter} for; + * never {@code null} + * @return a new {@code MethodParameter} + * @see #createSynthesizingMethodParameter(Parameter) + */ + public static MethodParameter createMethodParameter(Parameter parameter) { + Assert.notNull(parameter, "Parameter must not be null"); + Executable executable = parameter.getDeclaringExecutable(); + if (executable instanceof Method) { + return new MethodParameter((Method) executable, getIndex(parameter)); + } + // else + return new MethodParameter((Constructor) executable, getIndex(parameter)); + } + + /** + * Create a {@link SynthesizingMethodParameter} from the supplied {@link Parameter}. + *

Supports parameters declared in methods. + * @param parameter the parameter to create a {@code SynthesizingMethodParameter} + * for; never {@code null} + * @return a new {@code SynthesizingMethodParameter} + * @throws UnsupportedOperationException if the supplied parameter is declared + * in a constructor + * @see #createMethodParameter(Parameter) + */ + public static SynthesizingMethodParameter createSynthesizingMethodParameter(Parameter parameter) { + Assert.notNull(parameter, "Parameter must not be null"); + Executable executable = parameter.getDeclaringExecutable(); + if (executable instanceof Method) { + return new SynthesizingMethodParameter((Method) executable, getIndex(parameter)); + } + // else + throw new UnsupportedOperationException( + "Cannot create a SynthesizingMethodParameter for a constructor parameter: " + parameter); + } + + private static int getIndex(Parameter parameter) { + Assert.notNull(parameter, "Parameter must not be null"); + Executable executable = parameter.getDeclaringExecutable(); + Parameter[] parameters = executable.getParameters(); + for (int i = 0; i < parameters.length; i++) { + if (parameters[i] == parameter) { + return i; + } + } + throw new IllegalStateException(String.format("Failed to resolve index of parameter [%s] in executable [%s]", + parameter, executable.toGenericString())); + } + +} diff --git a/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/support/ParameterAutowireUtils.java b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/support/ParameterAutowireUtils.java new file mode 100644 index 0000000000..2c21b8fcd8 --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/support/ParameterAutowireUtils.java @@ -0,0 +1,113 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter.support; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.Optional; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.beans.factory.config.DependencyDescriptor; +import org.springframework.context.ApplicationContext; +import org.springframework.core.MethodParameter; +import org.springframework.core.annotation.AnnotatedElementUtils; + +import static org.springframework.core.annotation.AnnotatedElementUtils.hasAnnotation; + +/** + * Collection of utilities related to autowiring of individual method parameters. + * + * @author Sam Brannen + * @since 5.0 + * @see MethodParameterFactory + * @see #isAutowirable(Parameter) + * @see #resolveDependency(Parameter, Class, ApplicationContext) + */ +public abstract class ParameterAutowireUtils { + + private ParameterAutowireUtils() { + /* no-op */ + } + + /** + * Determine if the supplied {@link Parameter} can potentially be + * autowired from an {@link ApplicationContext}. + *

Returns {@code true} if the supplied parameter is of type + * {@link ApplicationContext} (or a sub-type thereof) or is annotated or + * meta-annotated with {@link Autowired @Autowired}, + * {@link Qualifier @Qualifier}, or {@link Value @Value}. + * @see #resolveDependency(Parameter, Class, ApplicationContext) + */ + public static boolean isAutowirable(Parameter parameter) { + return ApplicationContext.class.isAssignableFrom(parameter.getType()) + || hasAnnotation(parameter, Autowired.class) + || hasAnnotation(parameter, Qualifier.class) + || hasAnnotation(parameter, Value.class); + } + + /** + * Resolve the dependency for the supplied {@link Parameter} from the + * supplied {@link ApplicationContext}. + *

Provides comprehensive autowiring support for individual method parameters + * on par with Spring's dependency injection facilities for autowired fields and + * methods, including support for {@link Autowired @Autowired}, + * {@link Qualifier @Qualifier}, and {@link Value @Value} with support for property + * placeholders and SpEL expressions in {@code @Value} declarations. + *

The dependency is required unless the parameter is annotated with + * {@link Autowired @Autowired} with the {@link Autowired#required required} + * flag set to {@code false}. + *

If an explicit qualifier is not declared, the name of the parameter + * will be used as the qualifier for resolving ambiguities. + * @param parameter the parameter whose dependency should be resolved + * @param containingClass the concrete class that contains the parameter; this may + * differ from the class that declares the parameter in that it may be a subclass + * thereof, potentially substituting type variables + * @param applicationContext the application context from which to resolve the + * dependency + * @return the resolved object, or {@code null} if none found + * @throws BeansException if dependency resolution failed + * @see #isAutowirable(Parameter) + * @see Autowired#required + * @see MethodParameterFactory#createSynthesizingMethodParameter(Parameter) + * @see AutowireCapableBeanFactory#resolveDependency(DependencyDescriptor, String) + */ + public static Object resolveDependency(Parameter parameter, Class containingClass, + ApplicationContext applicationContext) { + + boolean required = findMergedAnnotation(parameter, Autowired.class).map(Autowired::required).orElse(true); + MethodParameter methodParameter = (parameter.getDeclaringExecutable() instanceof Method + ? MethodParameterFactory.createSynthesizingMethodParameter(parameter) + : MethodParameterFactory.createMethodParameter(parameter)); + DependencyDescriptor descriptor = new DependencyDescriptor(methodParameter, required); + descriptor.setContainingClass(containingClass); + + return applicationContext.getAutowireCapableBeanFactory().resolveDependency(descriptor, null); + } + + private static Optional findMergedAnnotation(AnnotatedElement element, + Class annotationType) { + + return Optional.ofNullable(AnnotatedElementUtils.findMergedAnnotation(element, annotationType)); + } + +} diff --git a/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/support/package-info.java b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/support/package-info.java new file mode 100644 index 0000000000..07235151a6 --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/support/package-info.java @@ -0,0 +1,5 @@ +/** + * Internal support classes for integrating the Spring TestContext Framework + * with the JUnit Jupiter extension model in JUnit 5. + */ +package org.springframework.test.context.junit.jupiter.support; diff --git a/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/web/SpringJUnitWebConfig.java b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/web/SpringJUnitWebConfig.java new file mode 100644 index 0000000000..29b78d59ef --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/web/SpringJUnitWebConfig.java @@ -0,0 +1,107 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter.web; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.junit.jupiter.api.extension.ExtendWith; + +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.annotation.AliasFor; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.web.WebAppConfiguration; + +/** + * {@code @SpringJUnitWebConfig} is a composed annotation that combines + * {@link ExtendWith @ExtendWith(SpringExtension.class)} from JUnit Jupiter with + * {@link ContextConfiguration @ContextConfiguration} and + * {@link WebAppConfiguration @WebAppConfiguration} from the Spring TestContext + * Framework. + * + * @author Sam Brannen + * @since 5.0 + * @see ExtendWith + * @see SpringExtension + * @see ContextConfiguration + * @see WebAppConfiguration + * @see org.springframework.test.context.junit.jupiter.SpringJUnitConfig + */ +@ExtendWith(SpringExtension.class) +@ContextConfiguration +@WebAppConfiguration +@Documented +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface SpringJUnitWebConfig { + + /** + * Alias for {@link ContextConfiguration#classes}. + */ + @AliasFor(annotation = ContextConfiguration.class, attribute = "classes") + Class[] value() default {}; + + /** + * Alias for {@link ContextConfiguration#classes}. + */ + @AliasFor(annotation = ContextConfiguration.class) + Class[] classes() default {}; + + /** + * Alias for {@link ContextConfiguration#locations}. + */ + @AliasFor(annotation = ContextConfiguration.class) + String[] locations() default {}; + + /** + * Alias for {@link ContextConfiguration#initializers}. + */ + @AliasFor(annotation = ContextConfiguration.class) + Class>[] initializers() default {}; + + /** + * Alias for {@link ContextConfiguration#inheritLocations}. + */ + @AliasFor(annotation = ContextConfiguration.class) + boolean inheritLocations() default true; + + /** + * Alias for {@link ContextConfiguration#inheritInitializers}. + */ + @AliasFor(annotation = ContextConfiguration.class) + boolean inheritInitializers() default true; + + /** + * Alias for {@link ContextConfiguration#name}. + */ + @AliasFor(annotation = ContextConfiguration.class) + String name() default ""; + + /** + * Alias for {@link WebAppConfiguration#value}. + */ + @AliasFor(annotation = WebAppConfiguration.class, attribute = "value") + String resourcePath() default "src/main/webapp"; + +} diff --git a/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/web/package-info.java b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/web/package-info.java new file mode 100644 index 0000000000..d82b9ceba8 --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/web/package-info.java @@ -0,0 +1,5 @@ +/** + * Web support for integrating the Spring TestContext Framework + * with the JUnit Jupiter extension model in JUnit 5. + */ +package org.springframework.test.context.junit.jupiter.web; diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/SpringJUnitJupiterTestSuite.java b/spring-test/src/test/java/org/springframework/test/context/junit/SpringJUnitJupiterTestSuite.java new file mode 100644 index 0000000000..09b7a84ee7 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/SpringJUnitJupiterTestSuite.java @@ -0,0 +1,40 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit; + +import org.junit.platform.runner.IncludeEngines; +import org.junit.platform.runner.JUnitPlatform; +import org.junit.platform.runner.SelectPackages; +import org.junit.runner.RunWith; + +/** + * JUnit 4 based test suite for tests that involve the Spring TestContext + * Framework and JUnit Jupiter (a.k.a., JUnit 5). + * + *

This class intentionally does not reside in the "jupiter" package + * so that the entire "jupiter" package can be excluded from the Gradle + * build. This class is therefore responsible for executing all JUnit + * Jupiter based tests in Spring's official test suite. + * + * @author Sam Brannen + * @since 5.0 + */ +@RunWith(JUnitPlatform.class) +@IncludeEngines("junit-jupiter") +@SelectPackages("org.springframework.test.context.junit.jupiter") +public class SpringJUnitJupiterTestSuite { +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/ComposedSpringExtensionTestCase.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/ComposedSpringExtensionTestCase.java new file mode 100644 index 0000000000..5644bce036 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/ComposedSpringExtensionTestCase.java @@ -0,0 +1,75 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter; + +import java.util.List; + +import org.junit.jupiter.api.DisplayName; +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.junit.SpringJUnitJupiterTestSuite; +import org.springframework.test.context.junit.jupiter.comics.Person; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Integration tests which demonstrate the composability of annotations from + * JUnit Jupiter and the Spring TestContext Framework. + * + *

Note that {@link SpringJUnitConfig @SpringJUnitConfig} is meta-annotated + * with JUnit Jupiter's {@link ExtendWith @ExtendWith} and Spring's + * {@link ContextConfiguration @ContextConfiguration}. + * + *

To run these tests in an IDE, simply run {@link SpringJUnitJupiterTestSuite} + * as a JUnit 4 test. + * + * @author Sam Brannen + * @since 5.0 + * @see SpringExtension + * @see SpringJUnitConfig + * @see SpringExtensionTestCase + */ +@SpringJUnitConfig(TestConfig.class) +@DisplayName("@SpringJUnitConfig Tests") +class ComposedSpringExtensionTestCase { + + @Autowired + Person dilbert; + + @Autowired + List people; + + @Test + @DisplayName("ApplicationContext injected into method") + void applicationContextInjected(ApplicationContext applicationContext) { + assertNotNull(applicationContext, "ApplicationContext should have been injected into method by Spring"); + assertEquals(dilbert, applicationContext.getBean("dilbert", Person.class)); + } + + @Test + @DisplayName("Spring @Beans injected into fields") + void springBeansInjected() { + assertNotNull(dilbert, "Person should have been @Autowired by Spring"); + assertEquals("Dilbert", dilbert.getName(), "Person's name"); + assertEquals(2, people.size(), "Number of Person objects in context"); + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/SpringExtensionTestCase.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/SpringExtensionTestCase.java new file mode 100644 index 0000000000..2ca3bf59ca --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/SpringExtensionTestCase.java @@ -0,0 +1,198 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter; + +import java.util.List; +import java.util.Optional; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.api.TestReporter; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit.SpringJUnitJupiterTestSuite; +import org.springframework.test.context.junit.jupiter.comics.Cat; +import org.springframework.test.context.junit.jupiter.comics.Dog; +import org.springframework.test.context.junit.jupiter.comics.Person; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Integration tests which demonstrate that the Spring TestContext Framework can + * be used with JUnit Jupiter via the {@link SpringExtension}. + * + *

To run these tests in an IDE, simply run {@link SpringJUnitJupiterTestSuite} + * as a JUnit 4 test. + * + * @author Sam Brannen + * @since 5.0 + * @see SpringExtension + * @see ComposedSpringExtensionTestCase + */ +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = TestConfig.class) +@TestPropertySource(properties = "enigma = 42") +class SpringExtensionTestCase { + + @Autowired + Person dilbert; + + @Autowired + List people; + + @Autowired + Dog dog; + + @Autowired + Cat cat; + + @Autowired + List cats; + + @Value("${enigma}") + Integer enigma; + + @Test + void applicationContextInjectedIntoMethod(ApplicationContext applicationContext) { + assertNotNull(applicationContext, "ApplicationContext should have been injected by Spring"); + assertEquals(this.dilbert, applicationContext.getBean("dilbert", Person.class)); + } + + @Test + void genericApplicationContextInjectedIntoMethod(GenericApplicationContext applicationContext) { + assertNotNull(applicationContext, "GenericApplicationContext should have been injected by Spring"); + assertEquals(this.dilbert, applicationContext.getBean("dilbert", Person.class)); + } + + @Test + void autowiredFields() { + assertNotNull(this.dilbert, "Dilbert should have been @Autowired by Spring"); + assertEquals("Dilbert", this.dilbert.getName(), "Person's name"); + assertEquals(2, this.people.size(), "Number of people in context"); + + assertNotNull(this.dog, "Dogbert should have been @Autowired by Spring"); + assertEquals("Dogbert", this.dog.getName(), "Dog's name"); + + assertNotNull(this.cat, "Catbert should have been @Autowired by Spring as the @Primary cat"); + assertEquals("Catbert", this.cat.getName(), "Primary cat's name"); + assertEquals(2, this.cats.size(), "Number of cats in context"); + + assertNotNull(this.enigma, "Enigma should have been injected via @Value by Spring"); + assertEquals(new Integer(42), this.enigma, "enigma"); + } + + @Test + void autowiredParameterByTypeForSingleBean(@Autowired Dog dog) { + assertNotNull(dog, "Dogbert should have been @Autowired by Spring"); + assertEquals("Dogbert", dog.getName(), "Dog's name"); + } + + @Test + void autowiredParameterByTypeForPrimaryBean(@Autowired Cat primaryCat) { + assertNotNull(primaryCat, "Primary cat should have been @Autowired by Spring"); + assertEquals("Catbert", primaryCat.getName(), "Primary cat's name"); + } + + @Test + void autowiredParameterWithExplicitQualifier(@Qualifier("wally") Person person) { + assertNotNull(person, "Wally should have been @Autowired by Spring"); + assertEquals("Wally", person.getName(), "Person's name"); + } + + /** + * NOTE: Test code must be compiled with "-g" (debug symbols) or "-parameters" in order + * for the parameter name to be used as the qualifier; otherwise, use + * {@code @Qualifier("wally")}. + */ + @Test + void autowiredParameterWithImplicitQualifierBasedOnParameterName(@Autowired Person wally) { + assertNotNull(wally, "Wally should have been @Autowired by Spring"); + assertEquals("Wally", wally.getName(), "Person's name"); + } + + @Test + void autowiredParameterAsJavaUtilOptional(@Autowired Optional dog) { + assertNotNull(dog, "Optional dog should have been @Autowired by Spring"); + assertTrue(dog.isPresent(), "Value of Optional should be 'present'"); + assertEquals("Dogbert", dog.get().getName(), "Dog's name"); + } + + @Test + void autowiredParameterThatDoesNotExistAsJavaUtilOptional(@Autowired Optional number) { + assertNotNull(number, "Optional number should have been @Autowired by Spring"); + assertFalse(number.isPresent(), "Value of Optional number should not be 'present'"); + } + + @Test + void autowiredParameterThatDoesNotExistButIsNotRequired(@Autowired(required = false) Number number) { + assertNull(number, "Non-required number should have been @Autowired as 'null' by Spring"); + } + + @Test + void autowiredParameterOfList(@Autowired List peopleParam) { + assertNotNull(peopleParam, "list of people should have been @Autowired by Spring"); + assertEquals(2, peopleParam.size(), "Number of people in context"); + } + + @Test + void valueParameterWithPrimitiveType(@Value("99") int num) { + assertEquals(99, num); + } + + @Test + void valueParameterFromPropertyPlaceholder(@Value("${enigma}") Integer enigmaParam) { + assertNotNull(enigmaParam, "Enigma should have been injected via @Value by Spring"); + assertEquals(new Integer(42), enigmaParam, "enigma"); + } + + @Test + void valueParameterFromDefaultValueForPropertyPlaceholder(@Value("${bogus:false}") Boolean defaultValue) { + assertNotNull(defaultValue, "Default value should have been injected via @Value by Spring"); + assertEquals(false, defaultValue, "default value"); + } + + @Test + void valueParameterFromSpelExpression(@Value("#{@dilbert.name}") String name) { + assertNotNull(name, "Dilbert's name should have been injected via SpEL expression in @Value by Spring"); + assertEquals("Dilbert", name, "name from SpEL expression"); + } + + @Test + void valueParameterFromSpelExpressionWithNestedPropertyPlaceholder(@Value("#{'Hello ' + ${enigma}}") String hello) { + assertNotNull(hello, "hello should have been injected via SpEL expression in @Value by Spring"); + assertEquals("Hello 42", hello, "hello from SpEL expression"); + } + + @Test + void junitAndSpringMethodInjectionCombined(@Autowired Cat kittyCat, TestInfo testInfo, ApplicationContext context, + TestReporter testReporter) { + + assertNotNull(testInfo, "TestInfo should have been injected by JUnit"); + assertNotNull(testReporter, "TestReporter should have been injected by JUnit"); + + assertNotNull(context, "ApplicationContext should have been injected by Spring"); + assertNotNull(kittyCat, "Cat should have been @Autowired by Spring"); + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/SpringJUnit5AutowiredConstructorInjectionTestCase.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/SpringJUnit5AutowiredConstructorInjectionTestCase.java new file mode 100644 index 0000000000..dbc6a2f0f5 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/SpringJUnit5AutowiredConstructorInjectionTestCase.java @@ -0,0 +1,83 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit.SpringJUnitJupiterTestSuite; +import org.springframework.test.context.junit.jupiter.comics.Dog; +import org.springframework.test.context.junit.jupiter.comics.Person; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Integration tests which demonstrate support for {@link Autowired @Autowired} + * test class constructors with the Spring TestContext Framework and JUnit 5. + * + *

To run these tests in an IDE, simply run {@link SpringJUnitJupiterTestSuite} + * as a JUnit 4 test. + * + * @author Sam Brannen + * @since 5.0 + * @see SpringExtension + * @see SpringJUnit5ConstructorInjectionTestCase + */ +@SpringJUnitConfig(TestConfig.class) +@TestPropertySource(properties = "enigma = 42") +class SpringJUnit5AutowiredConstructorInjectionTestCase { + + final ApplicationContext applicationContext; + final Person dilbert; + final Dog dog; + final Integer enigma; + + @Autowired + SpringJUnit5AutowiredConstructorInjectionTestCase(ApplicationContext applicationContext, Person dilbert, Dog dog, + @Value("${enigma}") Integer enigma) { + + this.applicationContext = applicationContext; + this.dilbert = dilbert; + this.dog = dog; + this.enigma = enigma; + } + + @Test + void applicationContextInjected() { + assertNotNull(applicationContext, "ApplicationContext should have been injected by Spring"); + assertEquals(this.dilbert, applicationContext.getBean("dilbert", Person.class)); + } + + @Test + void beansInjected() { + assertNotNull(this.dilbert, "Dilbert should have been @Autowired by Spring"); + assertEquals("Dilbert", this.dilbert.getName(), "Person's name"); + + assertNotNull(this.dog, "Dogbert should have been @Autowired by Spring"); + assertEquals("Dogbert", this.dog.getName(), "Dog's name"); + } + + @Test + void propertyPlaceholderInjected() { + assertNotNull(this.enigma, "Enigma should have been injected via @Value by Spring"); + assertEquals(new Integer(42), this.enigma, "enigma"); + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/SpringJUnit5ConstructorInjectionTestCase.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/SpringJUnit5ConstructorInjectionTestCase.java new file mode 100644 index 0000000000..6725163fe1 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/SpringJUnit5ConstructorInjectionTestCase.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit.SpringJUnitJupiterTestSuite; +import org.springframework.test.context.junit.jupiter.comics.Dog; +import org.springframework.test.context.junit.jupiter.comics.Person; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Integration tests which demonstrate support for autowiring individual + * parameters in test class constructors using {@link Autowired @Autowired} + * and {@link Value @Value} with the Spring TestContext Framework and JUnit 5. + * + *

To run these tests in an IDE, simply run {@link SpringJUnitJupiterTestSuite} + * as a JUnit 4 test. + * + * @author Sam Brannen + * @since 5.0 + * @see SpringExtension + * @see SpringJUnit5AutowiredConstructorInjectionTestCase + */ +@SpringJUnitConfig(TestConfig.class) +@TestPropertySource(properties = "enigma = 42") +class SpringJUnit5ConstructorInjectionTestCase { + + final ApplicationContext applicationContext; + final Person dilbert; + final Dog dog; + final Integer enigma; + final TestInfo testInfo; + + SpringJUnit5ConstructorInjectionTestCase(ApplicationContext applicationContext, @Autowired Person dilbert, + @Autowired Dog dog, @Value("${enigma}") Integer enigma, TestInfo testInfo) { + + this.applicationContext = applicationContext; + this.dilbert = dilbert; + this.dog = dog; + this.enigma = enigma; + this.testInfo = testInfo; + } + + @Test + void applicationContextInjected() { + assertNotNull(applicationContext, "ApplicationContext should have been injected by Spring"); + assertEquals(this.dilbert, applicationContext.getBean("dilbert", Person.class)); + } + + @Test + void beansInjected() { + assertNotNull(this.dilbert, "Dilbert should have been @Autowired by Spring"); + assertEquals("Dilbert", this.dilbert.getName(), "Person's name"); + + assertNotNull(this.dog, "Dogbert should have been @Autowired by Spring"); + assertEquals("Dogbert", this.dog.getName(), "Dog's name"); + } + + @Test + void propertyPlaceholderInjected() { + assertNotNull(this.enigma, "Enigma should have been injected via @Value by Spring"); + assertEquals(new Integer(42), this.enigma, "enigma"); + } + + @Test + void testInfoInjected() { + assertNotNull(this.testInfo, "TestInfo should have been injected by JUnit"); + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/TestConfig.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/TestConfig.java new file mode 100644 index 0000000000..65827d5a61 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/TestConfig.java @@ -0,0 +1,67 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; +import org.springframework.test.context.junit.jupiter.comics.Cat; +import org.springframework.test.context.junit.jupiter.comics.Dog; +import org.springframework.test.context.junit.jupiter.comics.Person; + +/** + * Demo config for tests. + * + * @author Sam Brannen + * @since 5.0 + */ +@Configuration +public class TestConfig { + + @Bean + static PropertySourcesPlaceholderConfigurer placeholderConfigurer() { + return new PropertySourcesPlaceholderConfigurer(); + } + + @Bean + Person dilbert() { + return new Person("Dilbert"); + } + + @Bean + Person wally() { + return new Person("Wally"); + } + + @Bean + Dog dogbert() { + return new Dog("Dogbert"); + } + + @Primary + @Bean + Cat catbert() { + return new Cat("Catbert"); + } + + @Bean + Cat garfield() { + return new Cat("Garfield"); + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/comics/Cat.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/comics/Cat.java new file mode 100644 index 0000000000..a66c91d16c --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/comics/Cat.java @@ -0,0 +1,31 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter.comics; + +/** + * Demo class for tests. + * + * @author Sam Brannen + * @since 5.0 + */ +public class Cat extends Character { + + public Cat(String name) { + super(name); + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/comics/Character.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/comics/Character.java new file mode 100644 index 0000000000..89a2ef9e30 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/comics/Character.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter.comics; + +/** + * Demo class for tests. + * + * @author Sam Brannen + * @since 5.0 + */ +public abstract class Character { + + private final String name; + + Character(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/comics/Dog.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/comics/Dog.java new file mode 100644 index 0000000000..118332f919 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/comics/Dog.java @@ -0,0 +1,31 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter.comics; + +/** + * Demo class for tests. + * + * @author Sam Brannen + * @since 5.0 + */ +public class Dog extends Character { + + public Dog(String name) { + super(name); + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/comics/Person.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/comics/Person.java new file mode 100644 index 0000000000..590f144201 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/comics/Person.java @@ -0,0 +1,31 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter.comics; + +/** + * Demo class for tests. + * + * @author Sam Brannen + * @since 5.0 + */ +public class Person extends Character { + + public Person(String name) { + super(name); + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/defaultmethods/CatInterfaceDefaultMethodsTestCase.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/defaultmethods/CatInterfaceDefaultMethodsTestCase.java new file mode 100644 index 0000000000..d72660c9d4 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/defaultmethods/CatInterfaceDefaultMethodsTestCase.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter.defaultmethods; + +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.junit.jupiter.comics.Cat; + +/** + * Parameterized test class for integration tests that demonstrate support for + * interface default methods and Java generics in JUnit 5 test classes when used + * with the Spring TestContext Framework and the {@link SpringExtension}. + * + * @author Sam Brannen + * @since 5.0 + */ +class CatInterfaceDefaultMethodsTestCase implements GenericComicCharactersInterfaceDefaultMethodsTestCase { + + @Override + public int getExpectedNumCharacters() { + return 2; + } + + @Override + public String getExpectedName() { + return "Catbert"; + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/defaultmethods/DogInterfaceDefaultMethodsTestCase.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/defaultmethods/DogInterfaceDefaultMethodsTestCase.java new file mode 100644 index 0000000000..9270476589 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/defaultmethods/DogInterfaceDefaultMethodsTestCase.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter.defaultmethods; + +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.junit.jupiter.comics.Dog; + +/** + * Parameterized test class for integration tests that demonstrate support for + * interface default methods and Java generics in JUnit 5 test classes when used + * with the Spring TestContext Framework and the {@link SpringExtension}. + * + * @author Sam Brannen + * @since 5.0 + */ +class DogInterfaceDefaultMethodsTestCase implements GenericComicCharactersInterfaceDefaultMethodsTestCase { + + @Override + public int getExpectedNumCharacters() { + return 1; + } + + @Override + public String getExpectedName() { + return "Dogbert"; + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/defaultmethods/GenericComicCharactersInterfaceDefaultMethodsTestCase.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/defaultmethods/GenericComicCharactersInterfaceDefaultMethodsTestCase.java new file mode 100644 index 0000000000..4bd4d511f6 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/defaultmethods/GenericComicCharactersInterfaceDefaultMethodsTestCase.java @@ -0,0 +1,57 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter.defaultmethods; + +import java.util.List; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; +import org.springframework.test.context.junit.jupiter.TestConfig; +import org.springframework.test.context.junit.jupiter.comics.Character; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Interface for integration tests that demonstrate support for interface default + * methods and Java generics in JUnit Jupiter test classes when used with the Spring + * TestContext Framework and the {@link SpringExtension}. + * + * @author Sam Brannen + * @since 5.0 + */ +@SpringJUnitConfig(TestConfig.class) +interface GenericComicCharactersInterfaceDefaultMethodsTestCase { + + @Test + default void autowiredParameterWithParameterizedList(@Autowired List characters) { + assertEquals(getExpectedNumCharacters(), characters.size(), "Number of characters in context"); + } + + @Test + default void autowiredParameterWithGenericBean(@Autowired C character) { + assertNotNull(character, "Character should have been @Autowired by Spring"); + assertEquals(getExpectedName(), character.getName(), "character's name"); + } + + int getExpectedNumCharacters(); + + String getExpectedName(); + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/generics/CatTestCase.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/generics/CatTestCase.java new file mode 100644 index 0000000000..ab2b6b87b0 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/generics/CatTestCase.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter.generics; + +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.junit.jupiter.comics.Cat; + +/** + * Parameterized test class for integration tests that demonstrate support for + * Java generics in JUnit 5 test classes when used with the Spring TestContext + * Framework and the {@link SpringExtension}. + * + * @author Sam Brannen + * @since 5.0 + */ +class CatTestCase extends GenericComicCharactersTestCase { + + @Override + int getExpectedNumCharacters() { + return 2; + } + + @Override + String getExpectedName() { + return "Catbert"; + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/generics/DogTestCase.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/generics/DogTestCase.java new file mode 100644 index 0000000000..a07256cb15 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/generics/DogTestCase.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter.generics; + +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.junit.jupiter.comics.Dog; + +/** + * Parameterized test class for integration tests that demonstrate support for + * Java generics in JUnit 5 test classes when used with the Spring TestContext + * Framework and the {@link SpringExtension}. + * + * @author Sam Brannen + * @since 5.0 + */ +class DogTestCase extends GenericComicCharactersTestCase { + + @Override + int getExpectedNumCharacters() { + return 1; + } + + @Override + String getExpectedName() { + return "Dogbert"; + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/generics/GenericComicCharactersTestCase.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/generics/GenericComicCharactersTestCase.java new file mode 100644 index 0000000000..ce6bc23797 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/generics/GenericComicCharactersTestCase.java @@ -0,0 +1,67 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter.generics; + +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.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.junit.jupiter.TestConfig; +import org.springframework.test.context.junit.jupiter.comics.Character; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Abstract base class for integration tests that demonstrate support for + * Java generics in JUnit 5 test classes when used with the Spring TestContext + * Framework and the {@link SpringExtension}. + * + * @author Sam Brannen + * @since 5.0 + */ +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = TestConfig.class) +abstract class GenericComicCharactersTestCase { + + @Autowired + T character; + + @Autowired + List characters; + + @Test + void autowiredFields() { + assertNotNull(this.character, "Character should have been @Autowired by Spring"); + assertEquals(getExpectedName(), character.getName(), "character's name"); + assertEquals(getExpectedNumCharacters(), this.characters.size(), "Number of characters in context"); + } + + @Test + void autowiredParameterByTypeForSingleGenericBean(@Autowired T character) { + assertNotNull(character, "Character should have been @Autowired by Spring"); + assertEquals(getExpectedName(), character.getName(), "character's name"); + } + + abstract int getExpectedNumCharacters(); + + abstract String getExpectedName(); + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/web/MultipleWebRequestsSpringExtensionTestCase.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/web/MultipleWebRequestsSpringExtensionTestCase.java new file mode 100644 index 0000000000..a3d1b9fcd2 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/web/MultipleWebRequestsSpringExtensionTestCase.java @@ -0,0 +1,74 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter.web; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.http.MediaType; +import org.springframework.test.context.junit.SpringJUnitJupiterTestSuite; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.context.WebApplicationContext; + +import static org.hamcrest.CoreMatchers.*; +import static org.springframework.http.MediaType.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*; + +/** + * Integration tests which demonstrate how to set up a {@link MockMvc} + * instance in an {@link BeforeEach @BeforeEach} method with the + * {@link SpringExtension} (registered via a custom + * {@link SpringJUnitWebConfig @SpringJUnitWebConfig} composed annotation). + * + *

To run these tests in an IDE, simply run {@link SpringJUnitJupiterTestSuite} + * as a JUnit 4 test. + * + * @author Sam Brannen + * @since 5.0 + * @see SpringExtension + * @see SpringJUnitWebConfig + * @see org.springframework.test.context.junit.jupiter.web.WebSpringExtensionTestCase + */ +@SpringJUnitWebConfig(WebConfig.class) +class MultipleWebRequestsSpringExtensionTestCase { + + MockMvc mockMvc; + + @BeforeEach + void setUpMockMvc(WebApplicationContext wac) { + this.mockMvc = webAppContextSetup(wac) + .alwaysExpect(status().isOk()) + .alwaysExpect(content().contentTypeCompatibleWith(APPLICATION_JSON)) + .build(); + } + + @Test + void getPerson42() throws Exception { + this.mockMvc.perform(get("/person/42").accept(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.name", is("Dilbert"))); + } + + @Test + void getPerson99() throws Exception { + this.mockMvc.perform(get("/person/99").accept(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.name", is("Wally"))); + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/web/PersonController.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/web/PersonController.java new file mode 100644 index 0000000000..5863928027 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/web/PersonController.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter.web; + +import org.springframework.test.context.junit.jupiter.comics.Person; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author Sam Brannen + * @since 5.0 + */ +@RestController +class PersonController { + + @GetMapping("/person/{id}") + Person getPerson(@PathVariable long id) { + if (id == 42) { + return new Person("Dilbert"); + } + return new Person("Wally"); + } + +} \ No newline at end of file diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/web/WebConfig.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/web/WebConfig.java new file mode 100644 index 0000000000..b93f93036f --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/web/WebConfig.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter.web; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +/** + * @author Sam Brannen + * @since 5.0 + */ +@Configuration +@EnableWebMvc +class WebConfig { + + @Bean + PersonController personController() { + return new PersonController(); + } + +} \ No newline at end of file diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/web/WebSpringExtensionTestCase.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/web/WebSpringExtensionTestCase.java new file mode 100644 index 0000000000..7fe7e616e7 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/web/WebSpringExtensionTestCase.java @@ -0,0 +1,67 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit.jupiter.web; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import org.springframework.http.MediaType; +import org.springframework.test.context.junit.SpringJUnitJupiterTestSuite; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.context.WebApplicationContext; + +import static org.hamcrest.CoreMatchers.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*; + +/** + * Integration tests which demonstrate use of the Spring MVC Test Framework and + * the Spring TestContext Framework with JUnit Jupiter and the + * {@link SpringExtension} (via a custom + * {@link SpringJUnitWebConfig @SpringJUnitWebConfig} composed annotation). + * + *

Note how the {@link #springMvcTest(WebApplicationContext)} test method + * has the {@link WebApplicationContext} injected as a method parameter. + * This allows the {@link MockMvc} instance to be configured local to the + * test method without any fields in the test class. + * + *

To run these tests in an IDE, simply run {@link SpringJUnitJupiterTestSuite} + * as a JUnit 4 test. + * + * @author Sam Brannen + * @since 5.0 + * @see SpringExtension + * @see SpringJUnitWebConfig + * @see org.springframework.test.context.junit.jupiter.web.MultipleWebRequestsSpringExtensionTestCase + * @see org.springframework.test.context.junit.jupiter.SpringExtensionTests + * @see org.springframework.test.context.junit.jupiter.ComposedSpringExtensionTests + */ +@SpringJUnitWebConfig(WebConfig.class) +@DisplayName("Web SpringExtension Tests") +class WebSpringExtensionTestCase { + + @Test + void springMvcTest(WebApplicationContext wac) throws Exception { + webAppContextSetup(wac).build() + .perform(get("/person/42").accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.name", is("Dilbert"))); + } + +}