WebMvcTest 太贪心了
WebMvcTest is too greedy
我想在我的 Spring 引导应用程序中为单个控制器编写 WebMvcTest
测试。除其他外,我的应用程序中还有一些自定义 Converters
。尽管我要测试的这个特定控制器不需要它们,但 Spring 还是会尝试创建它们。
现在的问题是:那些自定义转换器需要来自我的应用程序的更多 bean,这些 bean 没有被 WebMvcTest
测试切片初始化。并且不想模拟与特定测试完全无关的数十个 bean。除了在 excludeFilters
中手动指定它们之外,从特定 WebMvcTest
测试中排除某些 Web 组件的最佳做法是什么?
对于自定义测试,不要使用 WebMvcTest,创建自定义配置:
@SpringBootTest
@WebAppConfiguration
@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SomeYourTestConfiguration.class})
public class TestClass {
private MockMvc mockMvc;
@Before
public void setup() {
var someController = new SomeController();
mockMvc = MockMvcBuilders.standaloneSetup(someController).addFilters(...)
.setMessageConverters(...).setControllerAdvice(...).setValidator(...);
}
@Test
public void test() {
//arrange
when(...).thenReturn(...);
//act
var response = mockMvc.perform(...).andReturn().getResponse();
//assert
...
}
}
您可以根据需要配置 mockMvc
。
您可以使用自定义排除过滤器以避免将转换器加载到应用程序上下文中:
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = YourController.class, excludeFilters = @ComponentScan.Filter(type = CUSTOM, classes = NoConvertersFilter.class))
public class YourControllerTest {
...
}
class NoConvertersFilter extends TypeExcludeFilter {
private static final String CONVERTER_INTERFACE_NAME = Converter.class.getName();
@Override
public boolean match(@NonNull final MetadataReader metadataReader, @NonNull final MetadataReaderFactory metadataReaderFactory) throws IOException {
return Arrays.asList(metadataReader.getClassMetadata().getInterfaceNames()).contains(CONVERTER_INTERFACE_NAME);
}
}
使用这种方法,您只需将 excludeFilter 添加到那些您不想在其中加载转换器的控制器。如果添加了新的转换器,不用担心:它会自动排除,只要它实现了转换器接口。
我想在我的 Spring 引导应用程序中为单个控制器编写 WebMvcTest
测试。除其他外,我的应用程序中还有一些自定义 Converters
。尽管我要测试的这个特定控制器不需要它们,但 Spring 还是会尝试创建它们。
现在的问题是:那些自定义转换器需要来自我的应用程序的更多 bean,这些 bean 没有被 WebMvcTest
测试切片初始化。并且不想模拟与特定测试完全无关的数十个 bean。除了在 excludeFilters
中手动指定它们之外,从特定 WebMvcTest
测试中排除某些 Web 组件的最佳做法是什么?
对于自定义测试,不要使用 WebMvcTest,创建自定义配置:
@SpringBootTest
@WebAppConfiguration
@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SomeYourTestConfiguration.class})
public class TestClass {
private MockMvc mockMvc;
@Before
public void setup() {
var someController = new SomeController();
mockMvc = MockMvcBuilders.standaloneSetup(someController).addFilters(...)
.setMessageConverters(...).setControllerAdvice(...).setValidator(...);
}
@Test
public void test() {
//arrange
when(...).thenReturn(...);
//act
var response = mockMvc.perform(...).andReturn().getResponse();
//assert
...
}
}
您可以根据需要配置 mockMvc
。
您可以使用自定义排除过滤器以避免将转换器加载到应用程序上下文中:
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = YourController.class, excludeFilters = @ComponentScan.Filter(type = CUSTOM, classes = NoConvertersFilter.class))
public class YourControllerTest {
...
}
class NoConvertersFilter extends TypeExcludeFilter {
private static final String CONVERTER_INTERFACE_NAME = Converter.class.getName();
@Override
public boolean match(@NonNull final MetadataReader metadataReader, @NonNull final MetadataReaderFactory metadataReaderFactory) throws IOException {
return Arrays.asList(metadataReader.getClassMetadata().getInterfaceNames()).contains(CONVERTER_INTERFACE_NAME);
}
}
使用这种方法,您只需将 excludeFilter 添加到那些您不想在其中加载转换器的控制器。如果添加了新的转换器,不用担心:它会自动排除,只要它实现了转换器接口。