le-*_*ude 2 java spring unit-testing spring-mvc mockito
我热衷于干净、隔离良好的单元测试。但我在这里偶然发现了“干净”部分,用于测试控制器,该控制器使用DomainClassConverter功能来获取实体作为其映射方法的参数。
@Entity
class MyEntity {
@Id
private Integer id;
// rest of properties goes here.
}
Run Code Online (Sandbox Code Playgroud)
控制器是这样定义的
@RequestMapping("/api/v1/myentities")
class MyEntitiesController {
@Autowired
private DoSomethingService aService;
@PostMapping("/{id}")
public ResponseEntity<MyEntity> update(@PathVariable("id")Optional<MyEntity> myEntity) {
// do what is needed here
}
}
Run Code Online (Sandbox Code Playgroud)
因此,从小DomainClassConverter文档中我知道它用于CrudRepository#findById查找实体。我想知道的是如何在测试中干净地模拟它。我通过执行以下步骤取得了一些成功:
问题是设置代码很复杂,因此很难调试和解释(我的团队 99% 都是来自 Rails 或 Uni 的初级人员,所以我们必须保持简单)。我想知道是否有一种方法可以MyEntity从单元测试中注入所需的实例,同时继续使用@Autowired MockMvc.
CrudRepository目前我正在尝试是否可以注入for的模拟,MyEntity但没有成功。我已经有几年没有使用 Spring/Java 了(4),所以我对可用工具的了解可能不是最新的。
因此,从 DomainClassConverter 小文档中我知道它使用 CrudRepository#findById 来查找实体。我想知道的是如何在测试中干净地模拟它。
您将需要模拟在 之前调用的 2 个方法,CrudRepository#findById以便返回您想要的实体。下面的示例使用的是RestAssuredMockMvc,但是如果您WebApplicationContext也注入 ,则可以使用 MockMvc 执行相同的操作。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SomeApplication.class)
public class SomeControllerTest {
@Autowired
private WebApplicationContext context;
@MockBean(name = "mvcConversionService")
private WebConversionService webConversionService;
@Before
public void setup() {
RestAssuredMockMvc.webAppContextSetup(context);
SomeEntity someEntity = new SomeEntity();
when(webConversionService.canConvert(any(TypeDescriptor.class), any(TypeDescriptor.class)))
.thenReturn(true);
when(webConversionService.convert(eq("1"), any(TypeDescriptor.class), any(TypeDescriptor.class)))
.thenReturn(someEntity);
}
}
Run Code Online (Sandbox Code Playgroud)
在某些时候,Spring Boot 将执行WebConversionService::convert,DomainClassConverter::convert稍后将调用类似的内容invoker.invokeFindById,它将使用实体存储库来查找实体。
那么为什么要嘲笑WebConversionService而不是呢DomainClassConverter?因为DomainClassConverter是在应用程序启动期间实例化而无需注入:
DomainClassConverter<FormattingConversionService> converter =
new DomainClassConverter<>(conversionService);
Run Code Online (Sandbox Code Playgroud)
同时,WebConversionService是一个允许我们模拟它的 bean:
@Bean
@Override
public FormattingConversionService mvcConversionService() {
WebConversionService conversionService = new WebConversionService(this.mvcProperties.getDateFormat());
addFormatters(conversionService);
return conversionService;
}
Run Code Online (Sandbox Code Playgroud)
将模拟 bean 命名为 很重要mvcConversionService,否则它不会替换原始 bean。
关于存根,您需要模拟 2 个方法。首先你必须告诉你的模拟可以转换任何东西:
when(webConversionService.canConvert(any(TypeDescriptor.class), any(TypeDescriptor.class)))
.thenReturn(true);
Run Code Online (Sandbox Code Playgroud)
然后是 main 方法,它将匹配 URL 路径中定义的所需实体 ID:
when(webConversionService.convert(eq("1"), any(TypeDescriptor.class), any(TypeDescriptor.class)))
.thenReturn(someEntity);
Run Code Online (Sandbox Code Playgroud)
到目前为止,一切都很好。但也匹配目的地类型不是更好吗?就像是eq(TypeDescriptor.valueOf(SomeEntity.class))?可以,但是这会创建一个 TypeDescriptor 的新实例,当在域转换期间调用此存根时,该实例将不匹配。
这是我使用过的最干净的解决方案,但我知道如果 Spring 允许的话,效果可能会好得多。
| 归档时间: |
|
| 查看次数: |
634 次 |
| 最近记录: |