我认为Web应用程序运行良好。现在我正在尝试为它编写单元测试。我的webapp具有以下conversionService
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="....Class1ToStringConverter"/>
<bean class="....StringToClass1Converter"/>
</list>
</property>
</bean>
<mvc:annotation-driven conversion-service="conversionService" />
当我向
提出请求时,这很有效/somepath/{class1-object-string-representation}/xx
一切都按预期工作(字符串被解释为Class1对象)。
我的问题是尝试将单元测试写入控制器。转换服务只是没有使用,春天只告诉我
Cannot convert value of type [java.lang.String] to required type [Class1]: no matching editors or conversion strategy found
到目前为止我的测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/applicationContext.xml", "file:src/main/webapp/WEB-INF/jpm-servlet.xml"})
@WebAppConfiguration()
public class GeneralTest {
@Autowired
private WebApplicationContext ctx;
private MockMvc mockMvc;
private TestDAO testDAO = org.mockito.Mockito.mock(TestDAO.class);
@Before
public void setUp() throws Exception {
Mockito.reset(testDAO);
mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build();
}
@Test
public void testList() throws Exception {
final Test first = new Test(1L, "Hi", 10, new Date(), true);
final Test second = new Test(2L, "Bye", 50, new Date(), false);
first.setTest(second);
when(testDAO.list()).thenReturn(Arrays.asList(first, second));
mockMvc.perform(get("/jpm/class1-id1"))
.andExpect(status().isOk())
.andExpect(view().name("list"))
.andExpect(forwardedUrl("/WEB-INF/jsp/list.jsp"));
}
我失踪了什么?感谢
答案 0 :(得分:3)
Mock Converter就像这样,
GenericConversionService conversionService = new GenericConversionService();
conversionService.addConverter(new StringToClass1Converter());
Deencapsulation.setField(FIXTURE, conversionService);
答案 1 :(得分:0)
我有同样的问题。如果您尝试测试单个控制器,可以尝试以下操作:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/applicationContext.xml", "file:src/main/webapp/WEB-INF/jpm-servlet.xml"})
@WebAppConfiguration()
public class GeneralTest {
@Autowired
private WebApplicationContext ctx;
@Autowired
private FormattingConversionServiceFactoryBean conversionService;
private MockMvc mockMvc;
@Mock
private TestDAO testDAO;
/* The following assumes you are injecting your DAO into your controller
* If you are using a service layer (most likely), you should
* inject your DAO into your service and your service into your controller.
*/
@InjectMocks
private YourControllerClass controllerToTest;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
//get the conversion service from the factory bean
FormattingConversionService cs = conversionService.getObject();
Mockito.reset(testDAO);
//setup MockMvc using the conversion service
mockMvc = MockMvcBuilders.standaloneSetup(controllerToTest)
.setConversionService(cs)
.build();
}
@Test
public void testList() throws Exception {
final Test first = new Test(1L, "Hi", 10, new Date(), true);
final Test second = new Test(2L, "Bye", 50, new Date(), false);
first.setTest(second);
when(testDAO.list()).thenReturn(Arrays.asList(first, second));
mockMvc.perform(get("/jpm/class1-id1"))
.andExpect(status().isOk())
.andExpect(view().name("list"))
.andExpect(forwardedUrl("/WEB-INF/jsp/list.jsp"));
}
希望有所帮助!
答案 2 :(得分:0)
我意识到这是一个老线程,但是和我一样,在花了几个小时来解决为什么他们的自定义转换器没有被调用之后,其他人将来会偶然发现这个问题。
@Mariano D&#39; Ascanio提出的解决方案在没有控制器的情况下是不够的,至少不是您编写的控制器,例如当您使用Spring时JPA。 MockMvcBuilders.standaloneSetup
要求至少将一个控制器传递给构造函数,以便在这种情况下不能使用它。解决这个问题的方法是注入org.springframework.core.convert.converter.ConverterRegistry
或更好的,它的子类org.springframework.core.convert.converter.FormatterRegistry
,然后在@PostContruct
方法中注册您的自定义转换器/格式化程序,如下所示:
@PostConstruct
void init() {
formatterRegistry.removeConvertible(String.class, OffsetDateTime.class);
formatterRegistry.addFormatter(customOffsetDateTimeFormatter);
formatterRegistry.addConverter(customOffsetDateTimeConverter);
}
诀窍是使用名称而不是类型注入ConverterRegistry
,因为对于Web测试,有两个转换器注册表,默认值和mvc。 Spring测试使用默认转换器,因此是您需要的转换器。
// GOTCHA ALERT: There's also a mvcConversionService; tests DO NOT use that
@Resource(name = "defaultConversionService")
private FormatterRegistry formatterRegistry;
希望这有帮助。
答案 3 :(得分:0)
这篇文章有点过时,但在搜索此问题时仍然是Google的第一个结果。
所以这是 Spring Framework 5的更新。
当您配置Spring Documentation中记录的WebMvc上下文时,您可以这样写:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
// ...
}
}
但是,这是不在JUnit上下文中加载的!天知道为什么。但是你需要声明你的配置类:
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Override
public void addFormatters(FormatterRegistry registry) {
// ...
}
}
因此,删除@EnableWebMvc
注释并从另一个类扩展,如上所述。你可能不必改变其他任何东西。
然后,您的addFormatters
方法也会在您的单元测试中调用。
这是非常不直观和奇怪的。但这是真的。您可以使用断点调试spring-test源代码,并查看WebMvcConfigurer
接口的所有其他方法都被调用,但addFormatters
不是。也许他们只是忘了打电话或者他们有其他原因&#34;。通过从WebMvcConfigurationSupport
扩展,可以根据需要调用每个方法,并且您的JUnit测试成功。
特别是,此代码最终会被执行:
@Bean
public FormattingConversionService mvcConversionService() {
FormattingConversionService conversionService = new DefaultFormattingConversionService();
addFormatters(conversionService);
return conversionService;
}
老实说,当我按照Spring文档中的描述实现接口时,我不知道究竟是什么失败了。