Skip to content

Commit

Permalink
Fix nested test config discovery for sliced tests
Browse files Browse the repository at this point in the history
Fixes gh-23984
  • Loading branch information
wilkinsona committed Nov 2, 2020
1 parent 43b0e2f commit 8004a82
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 9 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 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.
Expand All @@ -21,12 +21,11 @@
import java.util.List;

import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextCustomizerFactory;
import org.springframework.test.context.TestContextAnnotationUtils;
import org.springframework.test.context.TestContextAnnotationUtils.AnnotationDescriptor;
import org.springframework.util.ObjectUtils;

/**
Expand All @@ -43,12 +42,13 @@ class TypeExcludeFiltersContextCustomizerFactory implements ContextCustomizerFac
@Override
public ContextCustomizer createContextCustomizer(Class<?> testClass,
List<ContextConfigurationAttributes> configurationAttributes) {
Class<?>[] filterClasses = MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)
.get(TypeExcludeFilters.class).getValue(MergedAnnotation.VALUE, Class[].class).orElse(NO_FILTERS);
AnnotationDescriptor<TypeExcludeFilters> descriptor = TestContextAnnotationUtils
.findAnnotationDescriptor(testClass, TypeExcludeFilters.class);
Class<?>[] filterClasses = (descriptor != null) ? descriptor.getAnnotation().value() : NO_FILTERS;
if (ObjectUtils.isEmpty(filterClasses)) {
return null;
}
return createContextCustomizer(testClass, filterClasses);
return createContextCustomizer(descriptor.getRootDeclaringClass(), filterClasses);
}

@SuppressWarnings("unchecked")
Expand Down
Expand Up @@ -30,6 +30,7 @@
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.test.context.TestContextAnnotationUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

Expand Down Expand Up @@ -58,6 +59,11 @@ public AnnotationsPropertySource(String name, Class<?> source) {

private Map<String, Object> getProperties(Class<?> source) {
Map<String, Object> properties = new LinkedHashMap<>();
getProperties(source, properties);
return properties;
}

private void getProperties(Class<?> source, Map<String, Object> properties) {
MergedAnnotations.from(source, SearchStrategy.SUPERCLASS).stream()
.filter(MergedAnnotationPredicates.unique(MergedAnnotation::getType)).forEach((annotation) -> {
Class<Annotation> type = annotation.getType();
Expand All @@ -70,7 +76,9 @@ private Map<String, Object> getProperties(Class<?> source) {
collectProperties(prefix, defaultSkip, annotation, attribute, properties);
}
});
return properties;
if (TestContextAnnotationUtils.searchEnclosingClass(source)) {
getProperties(source.getEnclosingClass(), properties);
}
}

private void collectProperties(String prefix, SkipPropertyMapping skip, MergedAnnotation<?> annotation,
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 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.
Expand All @@ -19,6 +19,7 @@
import org.junit.jupiter.api.Test;

import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizerFactoryTests.EnclosingClass.WithEnclosingClassExcludeFilters;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.type.classreading.MetadataReader;
Expand Down Expand Up @@ -55,6 +56,13 @@ void getContextCustomizerWhenHasAnnotationShouldReturnCustomizer() {
assertThat(customizer).isNotNull();
}

@Test
void getContextCustomizerWhenEnclosingClassHasAnnotationShouldReturnCustomizer() {
ContextCustomizer customizer = this.factory.createContextCustomizer(WithEnclosingClassExcludeFilters.class,
null);
assertThat(customizer).isNotNull();
}

@Test
void hashCodeAndEquals() {
ContextCustomizer customizer1 = this.factory.createContextCustomizer(WithExcludeFilters.class, null);
Expand Down Expand Up @@ -88,6 +96,15 @@ static class WithExcludeFilters {

}

@TypeExcludeFilters({ SimpleExclude.class, TestClassAwareExclude.class })
static class EnclosingClass {

class WithEnclosingClassExcludeFilters {

}

}

@TypeExcludeFilters({ TestClassAwareExclude.class, SimpleExclude.class })
static class WithSameExcludeFilters {

Expand Down
Expand Up @@ -19,10 +19,12 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import org.springframework.boot.test.autoconfigure.properties.AnnotationsPropertySourceTests.DeeplyNestedAnnotations.Level1;
import org.springframework.boot.test.autoconfigure.properties.AnnotationsPropertySourceTests.DeeplyNestedAnnotations.Level2;
import org.springframework.boot.test.autoconfigure.properties.AnnotationsPropertySourceTests.EnclosingClass.PropertyMappedAnnotationOnEnclosingClass;
import org.springframework.boot.test.autoconfigure.properties.AnnotationsPropertySourceTests.NestedAnnotations.Entry;
import org.springframework.core.annotation.AliasFor;

Expand Down Expand Up @@ -155,6 +157,14 @@ void typeLevelAnnotationOnSuperClass() {
assertThat(source.getProperty("value")).isEqualTo("abc");
}

@Test
void typeLevelAnnotationOnEnclosingClass() {
AnnotationsPropertySource source = new AnnotationsPropertySource(
PropertyMappedAnnotationOnEnclosingClass.class);
assertThat(source.getPropertyNames()).containsExactly("value");
assertThat(source.getProperty("value")).isEqualTo("abc");
}

@Test
void aliasedPropertyMappedAttributeOnSuperClass() {
AnnotationsPropertySource source = new AnnotationsPropertySource(
Expand Down Expand Up @@ -386,6 +396,15 @@ static class PropertyMappedAnnotationOnSuperClass extends TypeLevel {

}

@TypeLevelAnnotation("abc")
static class EnclosingClass {

class PropertyMappedAnnotationOnEnclosingClass {

}

}

static class AliasedPropertyMappedAnnotationOnSuperClass extends PropertyMappedAttributeWithAnAlias {

}
Expand Down Expand Up @@ -466,4 +485,14 @@ static class PropertyMappedWithDeeplyNestedAnnotations {

}

@TypeLevelAnnotation("outer")
static class OuterWithTypeLevel {

@Nested
static class NestedClass {

}

}

}
@@ -0,0 +1,70 @@
/*
* Copyright 2012-2020 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
*
* https://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.boot.test.autoconfigure.web.servlet.mockmvc;

import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

/**
* Tests for {@link WebMvcTest @WebMvcTest} using {@link Nested}.
*
* @author Andy Wilkinson
*/
@WebMvcTest(controllers = ExampleController2.class)
@WithMockUser
class WebMvcTestNestedIntegrationTests {

@Autowired
private MockMvc mvc;

@Test
void shouldNotFindController1() throws Exception {
this.mvc.perform(get("/one")).andExpect(status().isNotFound());
}

@Test
void shouldFindController2() throws Exception {
this.mvc.perform(get("/two")).andExpect(content().string("hellotwo")).andExpect(status().isOk());
}

@Nested
@WithMockUser
class NestedTests {

@Test
void shouldNotFindController1() throws Exception {
WebMvcTestNestedIntegrationTests.this.mvc.perform(get("/one")).andExpect(status().isNotFound());
}

@Test
void shouldFindController2() throws Exception {
WebMvcTestNestedIntegrationTests.this.mvc.perform(get("/two")).andExpect(content().string("hellotwo"))
.andExpect(status().isOk());
}

}

}

0 comments on commit 8004a82

Please sign in to comment.